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

Annotation of src/sys/ufs/ufs/ufs_lookup.c, Revision 1.32

1.32    ! mrg         1: /*     $NetBSD: ufs_lookup.c,v 1.31 2000/05/13 23:43:16 perseant Exp $ */
1.2       cgd         2:
1.1       mycroft     3: /*
                      4:  * Copyright (c) 1989, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  * (c) UNIX System Laboratories, Inc.
                      7:  * All or some portions of this file are derived from material licensed
                      8:  * to the University of California by American Telephone and Telegraph
                      9:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     10:  * the permission of UNIX System Laboratories, Inc.
                     11:  *
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 1. Redistributions of source code must retain the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer.
                     17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
                     19:  *    documentation and/or other materials provided with the distribution.
                     20:  * 3. All advertising materials mentioning features or use of this software
                     21:  *    must display the following acknowledgement:
                     22:  *     This product includes software developed by the University of
                     23:  *     California, Berkeley and its contributors.
                     24:  * 4. Neither the name of the University nor the names of its contributors
                     25:  *    may be used to endorse or promote products derived from this software
                     26:  *    without specific prior written permission.
                     27:  *
                     28:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     29:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     30:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     31:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     32:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     33:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     34:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     35:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     36:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     37:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     38:  * SUCH DAMAGE.
                     39:  *
1.3       mycroft    40:  *     @(#)ufs_lookup.c        8.9 (Berkeley) 8/11/94
1.1       mycroft    41:  */
                     42:
                     43: #include <sys/param.h>
1.7       christos   44: #include <sys/systm.h>
1.1       mycroft    45: #include <sys/namei.h>
                     46: #include <sys/buf.h>
                     47: #include <sys/file.h>
1.27      fvdl       48: #include <sys/stat.h>
1.1       mycroft    49: #include <sys/mount.h>
                     50: #include <sys/vnode.h>
1.27      fvdl       51: #include <sys/kernel.h>
1.1       mycroft    52:
                     53: #include <ufs/ufs/quota.h>
                     54: #include <ufs/ufs/inode.h>
                     55: #include <ufs/ufs/dir.h>
                     56: #include <ufs/ufs/ufsmount.h>
                     57: #include <ufs/ufs/ufs_extern.h>
1.15      bouyer     58: #include <ufs/ufs/ufs_bswap.h>
1.1       mycroft    59:
                     60: struct nchstats nchstats;
                     61: #ifdef DIAGNOSTIC
                     62: int    dirchk = 1;
                     63: #else
                     64: int    dirchk = 0;
                     65: #endif
                     66:
1.15      bouyer     67: #define FSFMT(vp)   ((vp)->v_mount->mnt_maxsymlinklen <= 0)
1.1       mycroft    68:
                     69: /*
                     70:  * Convert a component of a pathname into a pointer to a locked inode.
                     71:  * This is a very central and rather complicated routine.
                     72:  * If the file system is not maintained in a strict tree hierarchy,
                     73:  * this can result in a deadlock situation (see comments in code below).
                     74:  *
                     75:  * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending
                     76:  * on whether the name is to be looked up, created, renamed, or deleted.
                     77:  * When CREATE, RENAME, or DELETE is specified, information usable in
                     78:  * creating, renaming, or deleting a directory entry may be calculated.
                     79:  * If flag has LOCKPARENT or'ed into it and the target of the pathname
                     80:  * exists, lookup returns both the target and its parent directory locked.
                     81:  * When creating or renaming and LOCKPARENT is specified, the target may
                     82:  * not be ".".  When deleting and LOCKPARENT is specified, the target may
                     83:  * be "."., but the caller must check to ensure it does an vrele and vput
                     84:  * instead of two vputs.
                     85:  *
                     86:  * Overall outline of ufs_lookup:
                     87:  *
                     88:  *     check accessibility of directory
                     89:  *     look for name in cache, if found, then if at end of path
                     90:  *       and deleting or creating, drop it, else return name
                     91:  *     search for name in directory, to found or notfound
                     92:  * notfound:
                     93:  *     if creating, return locked directory, leaving info on available slots
                     94:  *     else return error
                     95:  * found:
                     96:  *     if at end of path and deleting, return information to allow delete
                     97:  *     if at end of path and rewriting (RENAME and LOCKPARENT), lock target
                     98:  *       inode and return info to allow rewrite
                     99:  *     if not at end, add name to cache; if at end and neither creating
                    100:  *       nor deleting, add name to cache
                    101:  */
                    102: int
1.7       christos  103: ufs_lookup(v)
                    104:        void *v;
                    105: {
1.1       mycroft   106:        struct vop_lookup_args /* {
                    107:                struct vnode *a_dvp;
                    108:                struct vnode **a_vpp;
                    109:                struct componentname *a_cnp;
1.7       christos  110:        } */ *ap = v;
1.30      augustss  111:        struct vnode *vdp;              /* vnode for directory being searched */
                    112:        struct inode *dp;               /* inode for directory being searched */
1.1       mycroft   113:        struct buf *bp;                 /* a buffer of directory entries */
1.30      augustss  114:        struct direct *ep;              /* the current directory entry */
1.1       mycroft   115:        int entryoffsetinblock;         /* offset of ep in bp's buffer */
                    116:        enum {NONE, COMPACT, FOUND} slotstatus;
                    117:        doff_t slotoffset;              /* offset of area with free space */
                    118:        int slotsize;                   /* size of area at slotoffset */
                    119:        int slotfreespace;              /* amount of space free in slot */
                    120:        int slotneeded;                 /* size of the entry we're seeking */
                    121:        int numdirpasses;               /* strategy for directory search */
                    122:        doff_t endsearch;               /* offset to end directory search */
                    123:        doff_t prevoff;                 /* prev entry dp->i_offset */
                    124:        struct vnode *pdp;              /* saved dp during symlink work */
                    125:        struct vnode *tdp;              /* returned by VFS_VGET */
                    126:        doff_t enduseful;               /* pointer past last used dir slot */
                    127:        u_long bmask;                   /* block offset mask */
                    128:        int lockparent;                 /* 1 => lockparent flag is set */
                    129:        int wantparent;                 /* 1 => wantparent or lockparent flag */
                    130:        int namlen, error;
                    131:        struct vnode **vpp = ap->a_vpp;
                    132:        struct componentname *cnp = ap->a_cnp;
                    133:        struct ucred *cred = cnp->cn_cred;
1.21      wrstuden  134:        int flags;
1.1       mycroft   135:        int nameiop = cnp->cn_nameiop;
1.15      bouyer    136:        const int needswap = UFS_MPNEEDSWAP(ap->a_dvp->v_mount);
1.1       mycroft   137:
1.21      wrstuden  138:        cnp->cn_flags &= ~PDIRUNLOCK;
                    139:        flags = cnp->cn_flags;
                    140:
1.1       mycroft   141:        bp = NULL;
                    142:        slotoffset = -1;
                    143:        *vpp = NULL;
                    144:        vdp = ap->a_dvp;
                    145:        dp = VTOI(vdp);
                    146:        lockparent = flags & LOCKPARENT;
                    147:        wantparent = flags & (LOCKPARENT|WANTPARENT);
                    148:
1.15      bouyer    149:
1.1       mycroft   150:        /*
                    151:         * Check accessiblity of directory.
                    152:         */
1.11      mycroft   153:        if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0)
1.1       mycroft   154:                return (error);
                    155:
1.14      fvdl      156:        if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
                    157:            (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
                    158:                return (EROFS);
                    159:
1.1       mycroft   160:        /*
                    161:         * We now have a segment name to search for, and a directory to search.
                    162:         *
                    163:         * Before tediously performing a linear scan of the directory,
                    164:         * check the name cache to see if the directory/name pair
                    165:         * we are looking for is known already.
                    166:         */
1.26      jdolecek  167:        if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
                    168:                return (error);
1.1       mycroft   169:
                    170:        /*
                    171:         * Suppress search for slots unless creating
                    172:         * file and at end of pathname, in which case
                    173:         * we watch for a place to put the new file in
                    174:         * case it doesn't already exist.
                    175:         */
                    176:        slotstatus = FOUND;
                    177:        slotfreespace = slotsize = slotneeded = 0;
                    178:        if ((nameiop == CREATE || nameiop == RENAME) &&
                    179:            (flags & ISLASTCN)) {
                    180:                slotstatus = NONE;
                    181:                slotneeded = (sizeof(struct direct) - MAXNAMLEN +
                    182:                        cnp->cn_namelen + 3) &~ 3;
                    183:        }
                    184:
                    185:        /*
                    186:         * If there is cached information on a previous search of
                    187:         * this directory, pick up where we last left off.
                    188:         * We cache only lookups as these are the most common
                    189:         * and have the greatest payoff. Caching CREATE has little
                    190:         * benefit as it usually must search the entire directory
                    191:         * to determine that the entry does not exist. Caching the
                    192:         * location of the last DELETE or RENAME has not reduced
                    193:         * profiling time and hence has been removed in the interest
                    194:         * of simplicity.
                    195:         */
                    196:        bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
                    197:        if (nameiop != LOOKUP || dp->i_diroff == 0 ||
1.13      bouyer    198:            dp->i_diroff > dp->i_ffs_size) {
1.1       mycroft   199:                entryoffsetinblock = 0;
                    200:                dp->i_offset = 0;
                    201:                numdirpasses = 1;
                    202:        } else {
                    203:                dp->i_offset = dp->i_diroff;
                    204:                if ((entryoffsetinblock = dp->i_offset & bmask) &&
                    205:                    (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)))
                    206:                        return (error);
                    207:                numdirpasses = 2;
                    208:                nchstats.ncs_2passes++;
                    209:        }
                    210:        prevoff = dp->i_offset;
1.13      bouyer    211:        endsearch = roundup(dp->i_ffs_size, DIRBLKSIZ);
1.1       mycroft   212:        enduseful = 0;
                    213:
                    214: searchloop:
                    215:        while (dp->i_offset < endsearch) {
                    216:                /*
                    217:                 * If necessary, get the next directory block.
                    218:                 */
                    219:                if ((dp->i_offset & bmask) == 0) {
                    220:                        if (bp != NULL)
                    221:                                brelse(bp);
1.7       christos  222:                        error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL,
                    223:                                             &bp);
                    224:                        if (error)
1.1       mycroft   225:                                return (error);
                    226:                        entryoffsetinblock = 0;
                    227:                }
                    228:                /*
                    229:                 * If still looking for a slot, and at a DIRBLKSIZE
                    230:                 * boundary, have to start looking for free space again.
                    231:                 */
                    232:                if (slotstatus == NONE &&
                    233:                    (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) {
                    234:                        slotoffset = -1;
                    235:                        slotfreespace = 0;
                    236:                }
                    237:                /*
                    238:                 * Get pointer to next entry.
                    239:                 * Full validation checks are slow, so we only check
                    240:                 * enough to insure forward progress through the
                    241:                 * directory. Complete checks can be run by patching
                    242:                 * "dirchk" to be true.
                    243:                 */
                    244:                ep = (struct direct *)((char *)bp->b_data + entryoffsetinblock);
                    245:                if (ep->d_reclen == 0 ||
1.7       christos  246:                    (dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock))) {
1.1       mycroft   247:                        int i;
                    248:
                    249:                        ufs_dirbad(dp, dp->i_offset, "mangled entry");
                    250:                        i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
                    251:                        dp->i_offset += i;
                    252:                        entryoffsetinblock += i;
                    253:                        continue;
                    254:                }
                    255:
                    256:                /*
                    257:                 * If an appropriate sized slot has not yet been found,
                    258:                 * check to see if one is available. Also accumulate space
                    259:                 * in the current block so that we can determine if
                    260:                 * compaction is viable.
                    261:                 */
                    262:                if (slotstatus != FOUND) {
1.15      bouyer    263:                        int size = ufs_rw16(ep->d_reclen, needswap);
1.1       mycroft   264:
                    265:                        if (ep->d_ino != 0)
1.15      bouyer    266:                                size -= DIRSIZ(FSFMT(vdp), ep, needswap);
1.1       mycroft   267:                        if (size > 0) {
                    268:                                if (size >= slotneeded) {
                    269:                                        slotstatus = FOUND;
                    270:                                        slotoffset = dp->i_offset;
1.15      bouyer    271:                                        slotsize = ufs_rw16(ep->d_reclen,
1.27      fvdl      272:                                                needswap);
1.1       mycroft   273:                                } else if (slotstatus == NONE) {
                    274:                                        slotfreespace += size;
                    275:                                        if (slotoffset == -1)
                    276:                                                slotoffset = dp->i_offset;
                    277:                                        if (slotfreespace >= slotneeded) {
                    278:                                                slotstatus = COMPACT;
                    279:                                                slotsize = dp->i_offset +
1.16      kleink    280:                                                    ufs_rw16(ep->d_reclen,
1.27      fvdl      281:                                                             needswap)
1.16      kleink    282:                                                    - slotoffset;
1.1       mycroft   283:                                        }
                    284:                                }
                    285:                        }
                    286:                }
                    287:
                    288:                /*
                    289:                 * Check for a name match.
                    290:                 */
                    291:                if (ep->d_ino) {
1.15      bouyer    292: #if (BYTE_ORDER == LITTLE_ENDIAN)
1.27      fvdl      293:                                if (vdp->v_mount->mnt_maxsymlinklen > 0 ||
                    294:                                    needswap != 0)
1.1       mycroft   295:                                        namlen = ep->d_namlen;
                    296:                                else
                    297:                                        namlen = ep->d_type;
1.15      bouyer    298: #else
1.27      fvdl      299:                                if (vdp->v_mount->mnt_maxsymlinklen <= 0
                    300:                                    && needswap != 0)
1.15      bouyer    301:                                        namlen = ep->d_type;
                    302:                                else
1.1       mycroft   303:                                namlen = ep->d_namlen;
1.15      bouyer    304: #endif
1.1       mycroft   305:                        if (namlen == cnp->cn_namelen &&
1.18      perry     306:                            !memcmp(cnp->cn_nameptr, ep->d_name,
1.1       mycroft   307:                                (unsigned)namlen)) {
                    308:                                /*
                    309:                                 * Save directory entry's inode number and
                    310:                                 * reclen in ndp->ni_ufs area, and release
                    311:                                 * directory buffer.
                    312:                                 */
1.4       mycroft   313:                                if (vdp->v_mount->mnt_maxsymlinklen > 0 &&
                    314:                                    ep->d_type == DT_WHT) {
1.3       mycroft   315:                                        slotstatus = FOUND;
                    316:                                        slotoffset = dp->i_offset;
1.16      kleink    317:                                        slotsize = ufs_rw16(ep->d_reclen,
                    318:                                            needswap);
1.3       mycroft   319:                                        dp->i_reclen = slotsize;
1.6       mycroft   320:                                        /*
                    321:                                         * This is used to set dp->i_endoff,
                    322:                                         * which may be used by ufs_direnter2()
                    323:                                         * as a length to truncate the
                    324:                                         * directory to.  Therefore, it must
                    325:                                         * point past the end of the last
                    326:                                         * non-empty directory entry.  We don't
                    327:                                         * know where that is in this case, so
                    328:                                         * we effectively disable shrinking by
                    329:                                         * using the existing size of the
                    330:                                         * directory.
                    331:                                         *
                    332:                                         * Note that we wouldn't expect to
                    333:                                         * shrink the directory while rewriting
                    334:                                         * an existing entry anyway.
                    335:                                         */
                    336:                                        enduseful = endsearch;
1.3       mycroft   337:                                        ap->a_cnp->cn_flags |= ISWHITEOUT;
                    338:                                        numdirpasses--;
                    339:                                        goto notfound;
                    340:                                }
1.15      bouyer    341:                                dp->i_ino = ufs_rw32(ep->d_ino, needswap);
                    342:                                dp->i_reclen = ufs_rw16(ep->d_reclen, needswap);
1.3       mycroft   343:                                brelse(bp);
1.1       mycroft   344:                                goto found;
                    345:                        }
                    346:                }
                    347:                prevoff = dp->i_offset;
1.15      bouyer    348:                dp->i_offset += ufs_rw16(ep->d_reclen, needswap);
                    349:                entryoffsetinblock += ufs_rw16(ep->d_reclen, needswap);
1.1       mycroft   350:                if (ep->d_ino)
                    351:                        enduseful = dp->i_offset;
                    352:        }
1.3       mycroft   353: notfound:
1.1       mycroft   354:        /*
                    355:         * If we started in the middle of the directory and failed
                    356:         * to find our target, we must check the beginning as well.
                    357:         */
                    358:        if (numdirpasses == 2) {
                    359:                numdirpasses--;
                    360:                dp->i_offset = 0;
                    361:                endsearch = dp->i_diroff;
                    362:                goto searchloop;
                    363:        }
                    364:        if (bp != NULL)
                    365:                brelse(bp);
                    366:        /*
                    367:         * If creating, and at end of pathname and current
                    368:         * directory has not been removed, then can consider
                    369:         * allowing file to be created.
                    370:         */
1.3       mycroft   371:        if ((nameiop == CREATE || nameiop == RENAME ||
                    372:             (nameiop == DELETE &&
                    373:              (ap->a_cnp->cn_flags & DOWHITEOUT) &&
                    374:              (ap->a_cnp->cn_flags & ISWHITEOUT))) &&
1.27      fvdl      375:            (flags & ISLASTCN) && dp->i_ffs_effnlink != 0) {
1.12      kleink    376:                /*
1.1       mycroft   377:                 * Access for write is interpreted as allowing
                    378:                 * creation of files in the directory.
                    379:                 */
1.7       christos  380:                error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
                    381:                if (error)
1.1       mycroft   382:                        return (error);
                    383:                /*
                    384:                 * Return an indication of where the new directory
                    385:                 * entry should be put.  If we didn't find a slot,
                    386:                 * then set dp->i_count to 0 indicating
                    387:                 * that the new slot belongs at the end of the
                    388:                 * directory. If we found a slot, then the new entry
                    389:                 * can be put in the range from dp->i_offset to
                    390:                 * dp->i_offset + dp->i_count.
                    391:                 */
                    392:                if (slotstatus == NONE) {
1.13      bouyer    393:                        dp->i_offset = roundup(dp->i_ffs_size, DIRBLKSIZ);
1.1       mycroft   394:                        dp->i_count = 0;
1.6       mycroft   395:                        enduseful = dp->i_offset;
1.3       mycroft   396:                } else if (nameiop == DELETE) {
                    397:                        dp->i_offset = slotoffset;
                    398:                        if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0)
                    399:                                dp->i_count = 0;
                    400:                        else
                    401:                                dp->i_count = dp->i_offset - prevoff;
1.1       mycroft   402:                } else {
                    403:                        dp->i_offset = slotoffset;
                    404:                        dp->i_count = slotsize;
                    405:                        if (enduseful < slotoffset + slotsize)
                    406:                                enduseful = slotoffset + slotsize;
                    407:                }
1.6       mycroft   408:                dp->i_endoff = roundup(enduseful, DIRBLKSIZ);
1.1       mycroft   409:                dp->i_flag |= IN_CHANGE | IN_UPDATE;
                    410:                /*
                    411:                 * We return with the directory locked, so that
                    412:                 * the parameters we set up above will still be
                    413:                 * valid if we actually decide to do a direnter().
                    414:                 * We return ni_vp == NULL to indicate that the entry
                    415:                 * does not currently exist; we leave a pointer to
                    416:                 * the (locked) directory inode in ndp->ni_dvp.
                    417:                 * The pathname buffer is saved so that the name
                    418:                 * can be obtained later.
                    419:                 *
                    420:                 * NB - if the directory is unlocked, then this
                    421:                 * information cannot be used.
                    422:                 */
                    423:                cnp->cn_flags |= SAVENAME;
1.21      wrstuden  424:                if (!lockparent) {
1.14      fvdl      425:                        VOP_UNLOCK(vdp, 0);
1.21      wrstuden  426:                        cnp->cn_flags |= PDIRUNLOCK;
                    427:                }
1.1       mycroft   428:                return (EJUSTRETURN);
                    429:        }
                    430:        /*
                    431:         * Insert name into cache (as non-existent) if appropriate.
                    432:         */
                    433:        if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
                    434:                cache_enter(vdp, *vpp, cnp);
                    435:        return (ENOENT);
                    436:
                    437: found:
                    438:        if (numdirpasses == 2)
                    439:                nchstats.ncs_pass2++;
                    440:        /*
                    441:         * Check that directory length properly reflects presence
                    442:         * of this entry.
                    443:         */
1.15      bouyer    444:        if (entryoffsetinblock + DIRSIZ(FSFMT(vdp), ep, needswap) >
                    445:                dp->i_ffs_size) {
1.1       mycroft   446:                ufs_dirbad(dp, dp->i_offset, "i_size too small");
1.15      bouyer    447:                dp->i_ffs_size = entryoffsetinblock +
                    448:                        DIRSIZ(FSFMT(vdp), ep, needswap);
1.1       mycroft   449:                dp->i_flag |= IN_CHANGE | IN_UPDATE;
                    450:        }
                    451:
                    452:        /*
                    453:         * Found component in pathname.
                    454:         * If the final component of path name, save information
                    455:         * in the cache as to where the entry was found.
                    456:         */
                    457:        if ((flags & ISLASTCN) && nameiop == LOOKUP)
                    458:                dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1);
                    459:
                    460:        /*
                    461:         * If deleting, and at end of pathname, return
                    462:         * parameters which can be used to remove file.
                    463:         * If the wantparent flag isn't set, we return only
                    464:         * the directory (in ndp->ni_dvp), otherwise we go
                    465:         * on and lock the inode, being careful with ".".
                    466:         */
                    467:        if (nameiop == DELETE && (flags & ISLASTCN)) {
                    468:                /*
                    469:                 * Write access to directory required to delete files.
                    470:                 */
1.7       christos  471:                error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
                    472:                if (error)
1.1       mycroft   473:                        return (error);
                    474:                /*
                    475:                 * Return pointer to current entry in dp->i_offset,
                    476:                 * and distance past previous entry (if there
                    477:                 * is a previous entry in this block) in dp->i_count.
                    478:                 * Save directory inode pointer in ndp->ni_dvp for dirremove().
                    479:                 */
                    480:                if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0)
                    481:                        dp->i_count = 0;
                    482:                else
                    483:                        dp->i_count = dp->i_offset - prevoff;
                    484:                if (dp->i_number == dp->i_ino) {
                    485:                        VREF(vdp);
                    486:                        *vpp = vdp;
                    487:                        return (0);
                    488:                }
1.28      fvdl      489:                if (flags & ISDOTDOT)
                    490:                        VOP_UNLOCK(vdp, 0); /* race to get the inode */
1.7       christos  491:                error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp);
1.28      fvdl      492:                if (flags & ISDOTDOT)
                    493:                        vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
1.7       christos  494:                if (error)
1.1       mycroft   495:                        return (error);
                    496:                /*
                    497:                 * If directory is "sticky", then user must own
                    498:                 * the directory, or the file in it, else she
                    499:                 * may not delete it (unless she's root). This
                    500:                 * implements append-only directories.
                    501:                 */
1.13      bouyer    502:                if ((dp->i_ffs_mode & ISVTX) &&
1.1       mycroft   503:                    cred->cr_uid != 0 &&
1.13      bouyer    504:                    cred->cr_uid != dp->i_ffs_uid &&
                    505:                    VTOI(tdp)->i_ffs_uid != cred->cr_uid) {
1.1       mycroft   506:                        vput(tdp);
                    507:                        return (EPERM);
                    508:                }
                    509:                *vpp = tdp;
1.21      wrstuden  510:                if (!lockparent) {
1.14      fvdl      511:                        VOP_UNLOCK(vdp, 0);
1.21      wrstuden  512:                        cnp->cn_flags |= PDIRUNLOCK;
                    513:                }
1.1       mycroft   514:                return (0);
                    515:        }
                    516:
                    517:        /*
                    518:         * If rewriting (RENAME), return the inode and the
                    519:         * information required to rewrite the present directory
                    520:         * Must get inode of directory entry to verify it's a
                    521:         * regular file, or empty directory.
                    522:         */
1.14      fvdl      523:        if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
1.7       christos  524:                error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
                    525:                if (error)
1.1       mycroft   526:                        return (error);
                    527:                /*
                    528:                 * Careful about locking second inode.
                    529:                 * This can only occur if the target is ".".
                    530:                 */
                    531:                if (dp->i_number == dp->i_ino)
                    532:                        return (EISDIR);
1.28      fvdl      533:                if (flags & ISDOTDOT)
                    534:                        VOP_UNLOCK(vdp, 0); /* race to get the inode */
1.7       christos  535:                error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp);
1.28      fvdl      536:                if (flags & ISDOTDOT)
                    537:                        vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
1.7       christos  538:                if (error)
1.1       mycroft   539:                        return (error);
                    540:                *vpp = tdp;
                    541:                cnp->cn_flags |= SAVENAME;
1.21      wrstuden  542:                if (!lockparent) {
1.14      fvdl      543:                        VOP_UNLOCK(vdp, 0);
1.21      wrstuden  544:                        cnp->cn_flags |= PDIRUNLOCK;
                    545:                }
1.1       mycroft   546:                return (0);
                    547:        }
                    548:
                    549:        /*
                    550:         * Step through the translation in the name.  We do not `vput' the
                    551:         * directory because we may need it again if a symbolic link
                    552:         * is relative to the current directory.  Instead we save it
                    553:         * unlocked as "pdp".  We must get the target inode before unlocking
                    554:         * the directory to insure that the inode will not be removed
                    555:         * before we get it.  We prevent deadlock by always fetching
                    556:         * inodes from the root, moving down the directory tree. Thus
                    557:         * when following backward pointers ".." we must unlock the
                    558:         * parent directory before getting the requested directory.
                    559:         * There is a potential race condition here if both the current
                    560:         * and parent directories are removed before the VFS_VGET for the
                    561:         * inode associated with ".." returns.  We hope that this occurs
                    562:         * infrequently since we cannot avoid this race condition without
                    563:         * implementing a sophisticated deadlock detection algorithm.
                    564:         * Note also that this simple deadlock detection scheme will not
                    565:         * work if the file system has any hard links other than ".."
                    566:         * that point backwards in the directory structure.
                    567:         */
                    568:        pdp = vdp;
                    569:        if (flags & ISDOTDOT) {
1.14      fvdl      570:                VOP_UNLOCK(pdp, 0);     /* race to get the inode */
1.21      wrstuden  571:                cnp->cn_flags |= PDIRUNLOCK;
1.7       christos  572:                error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp);
                    573:                if (error) {
1.21      wrstuden  574:                        if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY) == 0)
                    575:                                cnp->cn_flags &= ~PDIRUNLOCK;
1.1       mycroft   576:                        return (error);
                    577:                }
1.23      wrstuden  578:                if (lockparent && (flags & ISLASTCN)) {
1.25      wrstuden  579:                        if ((error = vn_lock(pdp, LK_EXCLUSIVE))) {
1.23      wrstuden  580:                                vput(tdp);
                    581:                                return (error);
                    582:                        }
                    583:                        cnp->cn_flags &= ~PDIRUNLOCK;
1.1       mycroft   584:                }
                    585:                *vpp = tdp;
                    586:        } else if (dp->i_number == dp->i_ino) {
                    587:                VREF(vdp);      /* we want ourself, ie "." */
                    588:                *vpp = vdp;
                    589:        } else {
1.7       christos  590:                error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp);
                    591:                if (error)
1.1       mycroft   592:                        return (error);
1.21      wrstuden  593:                if (!lockparent || !(flags & ISLASTCN)) {
1.14      fvdl      594:                        VOP_UNLOCK(pdp, 0);
1.21      wrstuden  595:                        cnp->cn_flags |= PDIRUNLOCK;
                    596:                }
1.1       mycroft   597:                *vpp = tdp;
                    598:        }
                    599:
                    600:        /*
                    601:         * Insert name into cache if appropriate.
                    602:         */
                    603:        if (cnp->cn_flags & MAKEENTRY)
                    604:                cache_enter(vdp, *vpp, cnp);
                    605:        return (0);
                    606: }
                    607:
                    608: void
                    609: ufs_dirbad(ip, offset, how)
                    610:        struct inode *ip;
                    611:        doff_t offset;
                    612:        char *how;
                    613: {
                    614:        struct mount *mp;
                    615:
                    616:        mp = ITOV(ip)->v_mount;
1.9       christos  617:        printf("%s: bad dir ino %d at offset %d: %s\n",
1.1       mycroft   618:            mp->mnt_stat.f_mntonname, ip->i_number, offset, how);
                    619:        if ((mp->mnt_stat.f_flags & MNT_RDONLY) == 0)
                    620:                panic("bad dir");
                    621: }
                    622:
                    623: /*
                    624:  * Do consistency checking on a directory entry:
                    625:  *     record length must be multiple of 4
                    626:  *     entry must fit in rest of its DIRBLKSIZ block
                    627:  *     record must be large enough to contain entry
                    628:  *     name is not longer than MAXNAMLEN
                    629:  *     name must be as long as advertised, and null terminated
                    630:  */
                    631: int
                    632: ufs_dirbadentry(dp, ep, entryoffsetinblock)
                    633:        struct vnode *dp;
1.30      augustss  634:        struct direct *ep;
1.1       mycroft   635:        int entryoffsetinblock;
                    636: {
1.30      augustss  637:        int i;
1.1       mycroft   638:        int namlen;
1.15      bouyer    639:        const int needswap = UFS_MPNEEDSWAP(dp->v_mount);
1.1       mycroft   640:
1.16      kleink    641: #if (BYTE_ORDER == LITTLE_ENDIAN)
                    642:        if (dp->v_mount->mnt_maxsymlinklen > 0 || needswap != 0)
                    643:                namlen = ep->d_namlen;
                    644:        else
                    645:                namlen = ep->d_type;
                    646: #else
1.19      fvdl      647:        if (dp->v_mount->mnt_maxsymlinklen <= 0 && needswap != 0)
1.16      kleink    648:                namlen = ep->d_type;
                    649:        else
1.27      fvdl      650:        namlen = ep->d_namlen;
1.16      kleink    651: #endif
1.15      bouyer    652:        if ((ufs_rw16(ep->d_reclen, needswap) & 0x3) != 0 ||
                    653:            ufs_rw16(ep->d_reclen, needswap) >
1.27      fvdl      654:                DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) ||
1.15      bouyer    655:            ufs_rw16(ep->d_reclen, needswap) <
1.27      fvdl      656:                DIRSIZ(FSFMT(dp), ep, needswap) ||
1.16      kleink    657:            namlen > MAXNAMLEN) {
1.1       mycroft   658:                /*return (1); */
1.20      thorpej   659:                printf("First bad, reclen=%x, DIRSIZ=%lu, namlen=%d, flags=%x "
1.15      bouyer    660:                        "entryoffsetinblock=%d\n",
                    661:                        ufs_rw16(ep->d_reclen, needswap),
1.20      thorpej   662:                        (u_long)DIRSIZ(FSFMT(dp), ep, needswap),
1.15      bouyer    663:                        namlen, dp->v_mount->mnt_flag, entryoffsetinblock);
1.1       mycroft   664:                goto bad;
                    665:        }
                    666:        if (ep->d_ino == 0)
                    667:                return (0);
                    668:        for (i = 0; i < namlen; i++)
                    669:                if (ep->d_name[i] == '\0') {
                    670:                        /*return (1); */
1.9       christos  671:                        printf("Second bad\n");
1.1       mycroft   672:                        goto bad;
                    673:        }
                    674:        if (ep->d_name[i])
                    675:                goto bad;
                    676:        return (0);
                    677: bad:
                    678:        return (1);
                    679: }
                    680:
                    681: /*
1.27      fvdl      682:  * Construct a new directory entry after a call to namei, using the
                    683:  * parameters that it left in the componentname argument cnp. The
                    684:  * argument ip is the inode to which the new directory entry will refer.
1.1       mycroft   685:  */
1.27      fvdl      686: void
                    687: ufs_makedirentry(ip, cnp, newdirp)
1.1       mycroft   688:        struct inode *ip;
1.27      fvdl      689:        struct componentname *cnp;
                    690:        struct direct *newdirp;
1.1       mycroft   691: {
                    692: #ifdef DIAGNOSTIC
                    693:        if ((cnp->cn_flags & SAVENAME) == 0)
1.27      fvdl      694:                panic("makedirentry: missing name");
1.1       mycroft   695: #endif
1.27      fvdl      696:        newdirp->d_ino = ip->i_number;
                    697:        newdirp->d_namlen = cnp->cn_namelen;
                    698:        memcpy(newdirp->d_name, cnp->cn_nameptr, (unsigned)cnp->cn_namelen + 1);
                    699:        if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0)
                    700:                newdirp->d_type = IFTODT(ip->i_ffs_mode);
                    701:        else {
                    702:                newdirp->d_type = 0;
                    703:        }
1.3       mycroft   704: }
                    705:
                    706: /*
1.27      fvdl      707:  * Write a directory entry after a call to namei, using the parameters
                    708:  * that it left in nameidata. The argument dirp is the new directory
                    709:  * entry contents. Dvp is a pointer to the directory to be written,
                    710:  * which was left locked by namei. Remaining parameters (dp->i_offset,
                    711:  * dp->i_count) indicate how the space for the new entry is to be obtained.
                    712:  * Non-null bp indicates that a directory is being created (for the
                    713:  * soft dependency code).
1.3       mycroft   714:  */
1.7       christos  715: int
1.27      fvdl      716: ufs_direnter(dvp, tvp, dirp, cnp, newdirbp)
1.3       mycroft   717:        struct vnode *dvp;
1.27      fvdl      718:        struct vnode *tvp;
1.3       mycroft   719:        struct direct *dirp;
1.27      fvdl      720:        struct componentname *cnp;
                    721:        struct buf *newdirbp;
                    722: {
1.3       mycroft   723:        struct ucred *cr;
                    724:        struct proc *p;
                    725:        int newentrysize;
                    726:        struct inode *dp;
                    727:        struct buf *bp;
                    728:        u_int dsize;
                    729:        struct direct *ep, *nep;
1.27      fvdl      730:        int error, ret, blkoff, loc, spacefree, flags;
1.3       mycroft   731:        char *dirbuf;
1.27      fvdl      732:        struct timespec ts;
1.15      bouyer    733:        const int needswap = UFS_MPNEEDSWAP(dvp->v_mount);
1.3       mycroft   734:
1.27      fvdl      735:        error = 0;
                    736:        cr = cnp->cn_cred;
                    737:        p = cnp->cn_proc;
                    738:
1.3       mycroft   739:        dp = VTOI(dvp);
1.15      bouyer    740:        newentrysize = DIRSIZ(0, dirp, 0);
1.3       mycroft   741:
1.1       mycroft   742:        if (dp->i_count == 0) {
                    743:                /*
                    744:                 * If dp->i_count is 0, then namei could find no
                    745:                 * space in the directory. Here, dp->i_offset will
                    746:                 * be on a directory block boundary and we will write the
                    747:                 * new entry into a fresh block.
                    748:                 */
                    749:                if (dp->i_offset & (DIRBLKSIZ - 1))
1.27      fvdl      750:                        panic("ufs_direnter: newblk");
                    751:                flags = B_CLRBUF;
                    752:                if (!DOINGSOFTDEP(dvp))
                    753:                        flags |= B_SYNC;
                    754:                if ((error = VOP_BALLOC(dvp, (off_t)dp->i_offset, DIRBLKSIZ,
                    755:                    cr, flags, &bp)) != 0) {
                    756:                        if (DOINGSOFTDEP(dvp) && newdirbp != NULL)
                    757:                                bdwrite(newdirbp);
                    758:                        return (error);
                    759:                }
                    760:                dp->i_ffs_size = dp->i_offset + DIRBLKSIZ;
                    761:                dp->i_flag |= IN_CHANGE | IN_UPDATE;
                    762:                uvm_vnp_setsize(dvp, dp->i_ffs_size);
1.15      bouyer    763:                dirp->d_reclen = ufs_rw16(DIRBLKSIZ, needswap);
                    764:                dirp->d_ino = ufs_rw32(dirp->d_ino, needswap);
1.27      fvdl      765:                if (dvp->v_mount->mnt_maxsymlinklen <= 0) {
1.15      bouyer    766: #if (BYTE_ORDER == LITTLE_ENDIAN)
1.16      kleink    767:                        if (needswap == 0) {
1.15      bouyer    768: #else
1.16      kleink    769:                        if (needswap != 0) {
1.15      bouyer    770: #endif
                    771:                                u_char tmp = dirp->d_namlen;
                    772:                                dirp->d_namlen = dirp->d_type;
                    773:                                dirp->d_type = tmp;
                    774:                        }
1.1       mycroft   775:                }
1.27      fvdl      776:                blkoff = dp->i_offset &
                    777:                    (VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1);
                    778:                memcpy((caddr_t)bp->b_data + blkoff, (caddr_t)dirp,
                    779:                    newentrysize);
                    780:                if (DOINGSOFTDEP(dvp)) {
                    781:                        /*
                    782:                         * Ensure that the entire newly allocated block is a
                    783:                         * valid directory so that future growth within the
                    784:                         * block does not have to ensure that the block is
                    785:                         * written before the inode.
                    786:                         */
                    787:                        blkoff += DIRBLKSIZ;
                    788:                        while (blkoff < bp->b_bcount) {
                    789:                                ((struct direct *)
                    790:                                   (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ;
                    791:                                blkoff += DIRBLKSIZ;
                    792:                        }
                    793:                        softdep_setup_directory_add(bp, dp, dp->i_offset,
                    794:                            ufs_rw32(dirp->d_ino, needswap), newdirbp);
                    795:                        bdwrite(bp);
                    796:                } else {
                    797:                        error = VOP_BWRITE(bp);
                    798:                }
                    799:                TIMEVAL_TO_TIMESPEC(&time, &ts);
1.31      perseant  800:                ret = VOP_UPDATE(dvp, &ts, &ts, UPDATE_DIROP);
1.27      fvdl      801:                if (error == 0)
                    802:                        return (ret);
1.1       mycroft   803:                return (error);
                    804:        }
                    805:
                    806:        /*
1.27      fvdl      807:         * If dp->i_count is non-zero, then namei found space for the new
                    808:         * entry in the range dp->i_offset to dp->i_offset + dp->i_count
                    809:         * in the directory. To use this space, we may have to compact
                    810:         * the entries located there, by copying them together towards the
                    811:         * beginning of the block, leaving the free space in one usable
                    812:         * chunk at the end.
1.1       mycroft   813:         */
                    814:
                    815:        /*
                    816:         * Increase size of directory if entry eats into new space.
                    817:         * This should never push the size past a new multiple of
                    818:         * DIRBLKSIZE.
                    819:         *
                    820:         * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
                    821:         */
1.13      bouyer    822:        if (dp->i_offset + dp->i_count > dp->i_ffs_size)
                    823:                dp->i_ffs_size = dp->i_offset + dp->i_count;
1.1       mycroft   824:        /*
                    825:         * Get the block containing the space for the new directory entry.
                    826:         */
1.7       christos  827:        error = VOP_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp);
1.27      fvdl      828:        if (error) {
                    829:                if (DOINGSOFTDEP(dvp) && newdirbp != NULL)
                    830:                        bdwrite(newdirbp);
1.1       mycroft   831:                return (error);
1.27      fvdl      832:        }
1.1       mycroft   833:        /*
                    834:         * Find space for the new entry. In the simple case, the entry at
                    835:         * offset base will have the space. If it does not, then namei
                    836:         * arranged that compacting the region dp->i_offset to
1.27      fvdl      837:         * dp->i_offset + dp->i_count would yield the space.
1.1       mycroft   838:         */
                    839:        ep = (struct direct *)dirbuf;
1.15      bouyer    840:        dsize = DIRSIZ(FSFMT(dvp), ep, needswap);
                    841:        spacefree = ufs_rw16(ep->d_reclen, needswap) - dsize;
                    842:        for (loc = ufs_rw16(ep->d_reclen, needswap); loc < dp->i_count; ) {
1.1       mycroft   843:                nep = (struct direct *)(dirbuf + loc);
                    844:                if (ep->d_ino) {
                    845:                        /* trim the existing slot */
1.15      bouyer    846:                        ep->d_reclen = ufs_rw16(dsize, needswap);
1.1       mycroft   847:                        ep = (struct direct *)((char *)ep + dsize);
                    848:                } else {
                    849:                        /* overwrite; nothing there; header is ours */
                    850:                        spacefree += dsize;
                    851:                }
1.15      bouyer    852:                dsize = DIRSIZ(FSFMT(dvp), nep, needswap);
                    853:                spacefree += ufs_rw16(nep->d_reclen, needswap) - dsize;
                    854:                loc += ufs_rw16(nep->d_reclen, needswap);
1.27      fvdl      855:                if (DOINGSOFTDEP(dvp))
                    856:                        softdep_change_directoryentry_offset(dp, dirbuf,
                    857:                            (caddr_t)nep, (caddr_t)ep, dsize);
                    858:                else
                    859:                        memcpy((caddr_t)ep, (caddr_t)nep, dsize);
1.1       mycroft   860:        }
                    861:        /*
                    862:         * Update the pointer fields in the previous entry (if any),
                    863:         * copy in the new entry, and write out the block.
                    864:         */
1.3       mycroft   865:        if (ep->d_ino == 0 ||
1.15      bouyer    866:            (ufs_rw32(ep->d_ino, needswap) == WINO &&
1.18      perry     867:             memcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) {
1.1       mycroft   868:                if (spacefree + dsize < newentrysize)
1.27      fvdl      869:                        panic("ufs_direnter: compact1");
1.3       mycroft   870:                dirp->d_reclen = spacefree + dsize;
1.1       mycroft   871:        } else {
                    872:                if (spacefree < newentrysize)
1.27      fvdl      873:                        panic("ufs_direnter: compact2");
1.3       mycroft   874:                dirp->d_reclen = spacefree;
1.15      bouyer    875:                ep->d_reclen = ufs_rw16(dsize, needswap);
1.1       mycroft   876:                ep = (struct direct *)((char *)ep + dsize);
                    877:        }
1.15      bouyer    878:        dirp->d_reclen = ufs_rw16(dirp->d_reclen, needswap);
                    879:        dirp->d_ino = ufs_rw32(dirp->d_ino, needswap);
1.27      fvdl      880:        if (dvp->v_mount->mnt_maxsymlinklen <= 0) {
1.15      bouyer    881: #if (BYTE_ORDER == LITTLE_ENDIAN)
1.16      kleink    882:                if (needswap == 0) {
1.15      bouyer    883: #else
1.16      kleink    884:                if (needswap != 0) {
1.15      bouyer    885: #endif
                    886:                        u_char tmp = dirp->d_namlen;
                    887:                        dirp->d_namlen = dirp->d_type;
                    888:                        dirp->d_type = tmp;
                    889:                }
1.27      fvdl      890:        }
1.18      perry     891:        memcpy((caddr_t)ep, (caddr_t)dirp, (u_int)newentrysize);
1.27      fvdl      892:        if (DOINGSOFTDEP(dvp)) {
                    893:                softdep_setup_directory_add(bp, dp,
                    894:                    dp->i_offset + (caddr_t)ep - dirbuf,
                    895:                        ufs_rw32(dirp->d_ino, needswap), newdirbp);
                    896:                bdwrite(bp);
                    897:        } else {
                    898:                error = VOP_BWRITE(bp);
                    899:        }
1.1       mycroft   900:        dp->i_flag |= IN_CHANGE | IN_UPDATE;
1.27      fvdl      901:        /*
                    902:         * If all went well, and the directory can be shortened, proceed
                    903:         * with the truncation. Note that we have to unlock the inode for
                    904:         * the entry that we just entered, as the truncation may need to
                    905:         * lock other inodes which can lead to deadlock if we also hold a
                    906:         * lock on the newly entered node.
                    907:         */
                    908:        if (error == 0 && dp->i_endoff && dp->i_endoff < dp->i_ffs_size) {
                    909:                if (tvp != NULL)
                    910:                        VOP_UNLOCK(tvp, 0);
                    911:                (void) VOP_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr, p);
                    912:                if (tvp != NULL)
                    913:                        vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
                    914:        }
1.1       mycroft   915:        return (error);
                    916: }
                    917:
                    918: /*
                    919:  * Remove a directory entry after a call to namei, using
                    920:  * the parameters which it left in nameidata. The entry
                    921:  * dp->i_offset contains the offset into the directory of the
                    922:  * entry to be eliminated.  The dp->i_count field contains the
                    923:  * size of the previous record in the directory.  If this
                    924:  * is 0, the first entry is being deleted, so we need only
                    925:  * zero the inode number to mark the entry as free.  If the
                    926:  * entry is not the first in the directory, we must reclaim
                    927:  * the space of the now empty record by adding the record size
                    928:  * to the size of the previous entry.
                    929:  */
                    930: int
1.27      fvdl      931: ufs_dirremove(dvp, ip, flags, isrmdir)
1.1       mycroft   932:        struct vnode *dvp;
1.27      fvdl      933:        struct inode *ip;
                    934:        int flags;
                    935:        int isrmdir;
1.1       mycroft   936: {
1.27      fvdl      937:        struct inode *dp;
1.1       mycroft   938:        struct direct *ep;
                    939:        struct buf *bp;
                    940:        int error;
                    941:
                    942:        dp = VTOI(dvp);
1.3       mycroft   943:
1.27      fvdl      944:        if (flags & DOWHITEOUT) {
1.3       mycroft   945:                /*
                    946:                 * Whiteout entry: set d_ino to WINO.
                    947:                 */
1.7       christos  948:                error = VOP_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep,
                    949:                                     &bp);
                    950:                if (error)
1.3       mycroft   951:                        return (error);
1.15      bouyer    952:                ep->d_ino = ufs_rw32(WINO, UFS_MPNEEDSWAP(dvp->v_mount));
1.3       mycroft   953:                ep->d_type = DT_WHT;
1.27      fvdl      954:                goto out;
                    955:        }
                    956:
                    957:        if ((error = VOP_BLKATOFF(dvp,
                    958:            (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0)
1.3       mycroft   959:                return (error);
                    960:
1.1       mycroft   961:        if (dp->i_count == 0) {
                    962:                /*
                    963:                 * First entry in block: set d_ino to zero.
                    964:                 */
                    965:                ep->d_ino = 0;
1.27      fvdl      966:        } else {
                    967:                /*
                    968:                 * Collapse new free space into previous entry.
                    969:                 */
                    970:                ep->d_reclen =
                    971:                    ufs_rw16(ufs_rw16(ep->d_reclen,
                    972:                                      UFS_MPNEEDSWAP(dvp->v_mount))
                    973:                             + dp->i_reclen, UFS_MPNEEDSWAP(dvp->v_mount));
                    974:        }
                    975: out:
                    976:        if (DOINGSOFTDEP(dvp)) {
1.28      fvdl      977:                if (ip) {
                    978:                        ip->i_ffs_effnlink--;
                    979:                        softdep_change_linkcnt(ip);
1.27      fvdl      980:                        softdep_setup_remove(bp, dp, ip, isrmdir);
1.28      fvdl      981:                }
1.27      fvdl      982:                bdwrite(bp);
                    983:        } else {
1.28      fvdl      984:                if (ip) {
                    985:                        ip->i_ffs_effnlink--;
1.27      fvdl      986:                        ip->i_ffs_nlink--;
1.28      fvdl      987:                        ip->i_flag |= IN_CHANGE;
                    988:                }
1.1       mycroft   989:                error = VOP_BWRITE(bp);
                    990:        }
                    991:        dp->i_flag |= IN_CHANGE | IN_UPDATE;
                    992:        return (error);
                    993: }
                    994:
                    995: /*
                    996:  * Rewrite an existing directory entry to point at the inode
                    997:  * supplied.  The parameters describing the directory entry are
                    998:  * set up by a call to namei.
                    999:  */
                   1000: int
1.27      fvdl     1001: ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir)
                   1002:        struct inode *dp, *oip;
                   1003:        ino_t newinum;
                   1004:        int newtype;
                   1005:        int isrmdir;
1.1       mycroft  1006: {
                   1007:        struct buf *bp;
                   1008:        struct direct *ep;
                   1009:        struct vnode *vdp = ITOV(dp);
                   1010:        int error;
                   1011:
1.7       christos 1012:        error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp);
                   1013:        if (error)
1.1       mycroft  1014:                return (error);
1.27      fvdl     1015:        ep->d_ino = ufs_rw32(newinum, UFS_MPNEEDSWAP(vdp->v_mount));
1.1       mycroft  1016:        if (vdp->v_mount->mnt_maxsymlinklen > 0)
1.27      fvdl     1017:                ep->d_type = newtype;
                   1018:        oip->i_ffs_effnlink--;
                   1019:        if (DOINGSOFTDEP(vdp)) {
1.28      fvdl     1020:                softdep_change_linkcnt(oip);
1.27      fvdl     1021:                softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir);
                   1022:                bdwrite(bp);
                   1023:        } else {
                   1024:                oip->i_ffs_nlink--;
1.28      fvdl     1025:                oip->i_flag |= IN_CHANGE;
1.27      fvdl     1026:                error = VOP_BWRITE(bp);
                   1027:        }
1.1       mycroft  1028:        dp->i_flag |= IN_CHANGE | IN_UPDATE;
                   1029:        return (error);
                   1030: }
                   1031:
                   1032: /*
                   1033:  * Check if a directory is empty or not.
                   1034:  * Inode supplied must be locked.
                   1035:  *
                   1036:  * Using a struct dirtemplate here is not precisely
                   1037:  * what we want, but better than using a struct direct.
                   1038:  *
                   1039:  * NB: does not handle corrupted directories.
                   1040:  */
                   1041: int
                   1042: ufs_dirempty(ip, parentino, cred)
1.30      augustss 1043:        struct inode *ip;
1.1       mycroft  1044:        ino_t parentino;
                   1045:        struct ucred *cred;
                   1046: {
1.30      augustss 1047:        off_t off;
1.1       mycroft  1048:        struct dirtemplate dbuf;
1.30      augustss 1049:        struct direct *dp = (struct direct *)&dbuf;
1.17      thorpej  1050:        int error, namlen;
                   1051:        size_t count;
1.1       mycroft  1052: #define        MINDIRSIZ (sizeof (struct dirtemplate) / 2)
                   1053:
1.15      bouyer   1054:        for (off = 0; off < ip->i_ffs_size;
1.27      fvdl     1055:            off += ufs_rw16(dp->d_reclen, UFS_IPNEEDSWAP(ip))) {
1.1       mycroft  1056:                error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off,
                   1057:                   UIO_SYSSPACE, IO_NODELOCKED, cred, &count, (struct proc *)0);
                   1058:                /*
                   1059:                 * Since we read MINDIRSIZ, residual must
                   1060:                 * be 0 unless we're at end of file.
                   1061:                 */
                   1062:                if (error || count != 0)
                   1063:                        return (0);
                   1064:                /* avoid infinite loops */
                   1065:                if (dp->d_reclen == 0)
                   1066:                        return (0);
                   1067:                /* skip empty entries */
1.15      bouyer   1068:                if (dp->d_ino == 0 ||
1.16      kleink   1069:                    ufs_rw32(dp->d_ino, UFS_IPNEEDSWAP(ip)) == WINO)
1.1       mycroft  1070:                        continue;
                   1071:                /* accept only "." and ".." */
1.16      kleink   1072: #if (BYTE_ORDER == LITTLE_ENDIAN)
                   1073:                if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0 ||
1.27      fvdl     1074:                   UFS_IPNEEDSWAP(ip) != 0)
1.16      kleink   1075:                        namlen = dp->d_namlen;
                   1076:                else
                   1077:                        namlen = dp->d_type;
                   1078: #else
1.19      fvdl     1079:                if (ITOV(ip)->v_mount->mnt_maxsymlinklen <= 0 &&
1.16      kleink   1080:                    UFS_IPNEEDSWAP(ip) != 0)
                   1081:                        namlen = dp->d_type;
                   1082:                else
                   1083:                        namlen = dp->d_namlen;
                   1084: #endif
1.1       mycroft  1085:                if (namlen > 2)
                   1086:                        return (0);
                   1087:                if (dp->d_name[0] != '.')
                   1088:                        return (0);
                   1089:                /*
                   1090:                 * At this point namlen must be 1 or 2.
                   1091:                 * 1 implies ".", 2 implies ".." if second
                   1092:                 * char is also "."
                   1093:                 */
1.27      fvdl     1094:                if (namlen == 1 &&
                   1095:                    ufs_rw32(dp->d_ino, UFS_IPNEEDSWAP(ip)) == ip->i_number)
1.1       mycroft  1096:                        continue;
1.15      bouyer   1097:                if (dp->d_name[1] == '.' &&
1.16      kleink   1098:                    ufs_rw32(dp->d_ino, UFS_IPNEEDSWAP(ip)) == parentino)
1.1       mycroft  1099:                        continue;
                   1100:                return (0);
                   1101:        }
                   1102:        return (1);
                   1103: }
                   1104:
                   1105: /*
                   1106:  * Check if source directory is in the path of the target directory.
                   1107:  * Target is supplied locked, source is unlocked.
                   1108:  * The target is always vput before returning.
                   1109:  */
                   1110: int
                   1111: ufs_checkpath(source, target, cred)
                   1112:        struct inode *source, *target;
                   1113:        struct ucred *cred;
                   1114: {
1.27      fvdl     1115:        struct vnode *vp = ITOV(target);
1.1       mycroft  1116:        int error, rootino, namlen;
                   1117:        struct dirtemplate dirbuf;
1.15      bouyer   1118:        const int needswap = UFS_MPNEEDSWAP(vp->v_mount);
1.1       mycroft  1119:
                   1120:        vp = ITOV(target);
                   1121:        if (target->i_number == source->i_number) {
                   1122:                error = EEXIST;
                   1123:                goto out;
                   1124:        }
                   1125:        rootino = ROOTINO;
                   1126:        error = 0;
                   1127:        if (target->i_number == rootino)
                   1128:                goto out;
                   1129:
                   1130:        for (;;) {
                   1131:                if (vp->v_type != VDIR) {
                   1132:                        error = ENOTDIR;
                   1133:                        break;
                   1134:                }
                   1135:                error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
1.27      fvdl     1136:                    sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
                   1137:                    IO_NODELOCKED, cred, NULL, (struct proc *)0);
1.1       mycroft  1138:                if (error != 0)
                   1139:                        break;
1.16      kleink   1140: #if (BYTE_ORDER == LITTLE_ENDIAN)
                   1141:                if (vp->v_mount->mnt_maxsymlinklen > 0 ||
1.27      fvdl     1142:                        needswap != 0)
1.16      kleink   1143:                        namlen = dirbuf.dotdot_namlen;
                   1144:                else
                   1145:                        namlen = dirbuf.dotdot_type;
                   1146: #else
1.27      fvdl     1147:                if (vp->v_mount->mnt_maxsymlinklen == 0 &&
1.16      kleink   1148:                    needswap != 0)
                   1149:                        namlen = dirbuf.dotdot_type;
                   1150:                else
1.1       mycroft  1151:                        namlen = dirbuf.dotdot_namlen;
1.16      kleink   1152: #endif
1.1       mycroft  1153:                if (namlen != 2 ||
                   1154:                    dirbuf.dotdot_name[0] != '.' ||
                   1155:                    dirbuf.dotdot_name[1] != '.') {
                   1156:                        error = ENOTDIR;
                   1157:                        break;
                   1158:                }
1.15      bouyer   1159:                if (ufs_rw32(dirbuf.dotdot_ino, needswap) == source->i_number) {
1.1       mycroft  1160:                        error = EINVAL;
                   1161:                        break;
                   1162:                }
1.15      bouyer   1163:                if (ufs_rw32(dirbuf.dotdot_ino, needswap) == rootino)
1.1       mycroft  1164:                        break;
                   1165:                vput(vp);
1.15      bouyer   1166:                error = VFS_VGET(vp->v_mount,
1.16      kleink   1167:                    ufs_rw32(dirbuf.dotdot_ino, needswap), &vp);
1.7       christos 1168:                if (error) {
1.1       mycroft  1169:                        vp = NULL;
                   1170:                        break;
                   1171:                }
                   1172:        }
                   1173:
                   1174: out:
                   1175:        if (error == ENOTDIR)
1.9       christos 1176:                printf("checkpath: .. not a directory\n");
1.1       mycroft  1177:        if (vp != NULL)
                   1178:                vput(vp);
                   1179:        return (error);
                   1180: }

CVSweb <webmaster@jp.NetBSD.org>