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

Annotation of src/sys/ufs/ufs/ufs_vnops.c, Revision 1.26

1.26    ! bouyer      1: /*     $NetBSD: ufs_vnops.c,v 1.25 1997/05/08 16:20:45 mycroft Exp $   */
1.3       cgd         2:
1.1       mycroft     3: /*
                      4:  * Copyright (c) 1982, 1986, 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.6       mycroft    40:  *     @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
1.1       mycroft    41:  */
                     42:
                     43: #include <sys/param.h>
                     44: #include <sys/systm.h>
                     45: #include <sys/namei.h>
                     46: #include <sys/resourcevar.h>
                     47: #include <sys/kernel.h>
                     48: #include <sys/file.h>
                     49: #include <sys/stat.h>
                     50: #include <sys/buf.h>
                     51: #include <sys/proc.h>
                     52: #include <sys/conf.h>
                     53: #include <sys/mount.h>
                     54: #include <sys/vnode.h>
                     55: #include <sys/malloc.h>
                     56: #include <sys/dirent.h>
                     57: #include <sys/lockf.h>
                     58:
                     59: #include <vm/vm.h>
                     60:
                     61: #include <miscfs/specfs/specdev.h>
1.15      christos   62: #include <miscfs/fifofs/fifo.h>
1.1       mycroft    63:
                     64: #include <ufs/ufs/quota.h>
                     65: #include <ufs/ufs/inode.h>
                     66: #include <ufs/ufs/dir.h>
                     67: #include <ufs/ufs/ufsmount.h>
                     68: #include <ufs/ufs/ufs_extern.h>
1.26    ! bouyer     69: #include <ufs/ext2fs/ext2fs_extern.h>
1.1       mycroft    70:
                     71: static int ufs_chmod __P((struct vnode *, int, struct ucred *, struct proc *));
                     72: static int ufs_chown
                     73:        __P((struct vnode *, uid_t, gid_t, struct ucred *, struct proc *));
                     74:
                     75: union _qcvt {
1.4       cgd        76:        int64_t qcvt;
                     77:        int32_t val[2];
1.1       mycroft    78: };
                     79: #define SETHIGH(q, h) { \
                     80:        union _qcvt tmp; \
                     81:        tmp.qcvt = (q); \
                     82:        tmp.val[_QUAD_HIGHWORD] = (h); \
                     83:        (q) = tmp.qcvt; \
                     84: }
                     85: #define SETLOW(q, l) { \
                     86:        union _qcvt tmp; \
                     87:        tmp.qcvt = (q); \
                     88:        tmp.val[_QUAD_LOWWORD] = (l); \
                     89:        (q) = tmp.qcvt; \
                     90: }
                     91:
                     92: /*
                     93:  * Create a regular file
                     94:  */
                     95: int
1.15      christos   96: ufs_create(v)
                     97:        void *v;
                     98: {
1.1       mycroft    99:        struct vop_create_args /* {
                    100:                struct vnode *a_dvp;
                    101:                struct vnode **a_vpp;
                    102:                struct componentname *a_cnp;
                    103:                struct vattr *a_vap;
1.15      christos  104:        } */ *ap = v;
                    105:        return
1.1       mycroft   106:            ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
1.15      christos  107:                          ap->a_dvp, ap->a_vpp, ap->a_cnp);
1.1       mycroft   108: }
                    109:
                    110: /*
                    111:  * Mknod vnode call
                    112:  */
                    113: /* ARGSUSED */
                    114: int
1.15      christos  115: ufs_mknod(v)
                    116:        void *v;
                    117: {
1.1       mycroft   118:        struct vop_mknod_args /* {
                    119:                struct vnode *a_dvp;
                    120:                struct vnode **a_vpp;
                    121:                struct componentname *a_cnp;
                    122:                struct vattr *a_vap;
1.15      christos  123:        } */ *ap = v;
1.1       mycroft   124:        register struct vattr *vap = ap->a_vap;
                    125:        register struct vnode **vpp = ap->a_vpp;
                    126:        register struct inode *ip;
                    127:        int error;
                    128:
1.15      christos  129:        if ((error =
1.1       mycroft   130:            ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
1.15      christos  131:            ap->a_dvp, vpp, ap->a_cnp)) != 0)
1.1       mycroft   132:                return (error);
                    133:        ip = VTOI(*vpp);
                    134:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
                    135:        if (vap->va_rdev != VNOVAL) {
                    136:                /*
                    137:                 * Want to be able to use this to make badblock
                    138:                 * inodes, so don't truncate the dev number.
                    139:                 */
1.26    ! bouyer    140:                ip->i_ffs_rdev = vap->va_rdev;
1.1       mycroft   141:        }
                    142:        /*
                    143:         * Remove inode so that it will be reloaded by VFS_VGET and
                    144:         * checked to see if it is an alias of an existing entry in
                    145:         * the inode cache.
                    146:         */
                    147:        vput(*vpp);
                    148:        (*vpp)->v_type = VNON;
                    149:        vgone(*vpp);
                    150:        *vpp = 0;
                    151:        return (0);
                    152: }
                    153:
                    154: /*
                    155:  * Open called.
                    156:  *
                    157:  * Nothing to do.
                    158:  */
                    159: /* ARGSUSED */
                    160: int
1.15      christos  161: ufs_open(v)
                    162:        void *v;
                    163: {
1.1       mycroft   164:        struct vop_open_args /* {
                    165:                struct vnode *a_vp;
                    166:                int  a_mode;
                    167:                struct ucred *a_cred;
                    168:                struct proc *a_p;
1.15      christos  169:        } */ *ap = v;
1.1       mycroft   170:
                    171:        /*
                    172:         * Files marked append-only must be opened for appending.
                    173:         */
1.26    ! bouyer    174:        if ((VTOI(ap->a_vp)->i_ffs_flags & APPEND) &&
1.1       mycroft   175:            (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
                    176:                return (EPERM);
                    177:        return (0);
                    178: }
                    179:
                    180: /*
                    181:  * Close called.
                    182:  *
                    183:  * Update the times on the inode.
                    184:  */
                    185: /* ARGSUSED */
                    186: int
1.15      christos  187: ufs_close(v)
                    188:        void *v;
                    189: {
1.1       mycroft   190:        struct vop_close_args /* {
                    191:                struct vnode *a_vp;
                    192:                int  a_fflag;
                    193:                struct ucred *a_cred;
                    194:                struct proc *a_p;
1.15      christos  195:        } */ *ap = v;
1.1       mycroft   196:        register struct vnode *vp = ap->a_vp;
                    197:        register struct inode *ip = VTOI(vp);
1.19      mycroft   198:        struct timespec ts;
1.1       mycroft   199:
1.19      mycroft   200:        if (vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED)) {
                    201:                TIMEVAL_TO_TIMESPEC(&time, &ts);
                    202:                ITIMES(ip, &ts, &ts, &ts);
                    203:        }
1.1       mycroft   204:        return (0);
                    205: }
                    206:
                    207: int
1.15      christos  208: ufs_access(v)
                    209:        void *v;
                    210: {
1.1       mycroft   211:        struct vop_access_args /* {
                    212:                struct vnode *a_vp;
                    213:                int  a_mode;
                    214:                struct ucred *a_cred;
                    215:                struct proc *a_p;
1.15      christos  216:        } */ *ap = v;
1.1       mycroft   217:        register struct vnode *vp = ap->a_vp;
                    218:        register struct inode *ip = VTOI(vp);
1.7       ws        219:        mode_t mode = ap->a_mode;
1.1       mycroft   220:
                    221: #ifdef DIAGNOSTIC
                    222:        if (!VOP_ISLOCKED(vp)) {
                    223:                vprint("ufs_access: not locked", vp);
                    224:                panic("ufs_access: not locked");
                    225:        }
                    226: #endif
                    227: #ifdef QUOTA
                    228:        if (mode & VWRITE)
                    229:                switch (vp->v_type) {
1.15      christos  230:                        int error;
1.1       mycroft   231:                case VDIR:
                    232:                case VLNK:
                    233:                case VREG:
1.15      christos  234:                        if ((error = getinoquota(ip)) != 0)
1.1       mycroft   235:                                return (error);
                    236:                        break;
1.15      christos  237:                case VBAD:
                    238:                case VBLK:
                    239:                case VCHR:
                    240:                case VSOCK:
                    241:                case VFIFO:
                    242:                case VNON:
                    243:                        break;
1.1       mycroft   244:                }
                    245: #endif
                    246:
                    247:        /* If immutable bit set, nobody gets to write it. */
1.26    ! bouyer    248:        if ((mode & VWRITE) && (ip->i_ffs_flags & IMMUTABLE))
1.1       mycroft   249:                return (EPERM);
                    250:
1.26    ! bouyer    251:        return (vaccess(vp->v_type, ip->i_ffs_mode & ALLPERMS,
        !           252:                ip->i_ffs_uid, ip->i_ffs_gid, mode, ap->a_cred));
1.1       mycroft   253: }
                    254:
                    255: /* ARGSUSED */
                    256: int
1.15      christos  257: ufs_getattr(v)
                    258:        void *v;
                    259: {
1.1       mycroft   260:        struct vop_getattr_args /* {
                    261:                struct vnode *a_vp;
                    262:                struct vattr *a_vap;
                    263:                struct ucred *a_cred;
                    264:                struct proc *a_p;
1.15      christos  265:        } */ *ap = v;
1.1       mycroft   266:        register struct vnode *vp = ap->a_vp;
                    267:        register struct inode *ip = VTOI(vp);
                    268:        register struct vattr *vap = ap->a_vap;
1.19      mycroft   269:        struct timespec ts;
1.1       mycroft   270:
1.19      mycroft   271:        TIMEVAL_TO_TIMESPEC(&time, &ts);
1.26    ! bouyer    272:        FFS_ITIMES(ip, &ts, &ts, &ts);
1.1       mycroft   273:        /*
                    274:         * Copy from inode table
                    275:         */
                    276:        vap->va_fsid = ip->i_dev;
                    277:        vap->va_fileid = ip->i_number;
1.26    ! bouyer    278:        vap->va_mode = ip->i_ffs_mode & ALLPERMS;
        !           279:        vap->va_nlink = ip->i_ffs_nlink;
        !           280:        vap->va_uid = ip->i_ffs_uid;
        !           281:        vap->va_gid = ip->i_ffs_gid;
        !           282:        vap->va_rdev = (dev_t)ip->i_ffs_rdev;
        !           283:        vap->va_size = ip->i_ffs_size;
        !           284:        vap->va_atime.tv_sec = ip->i_ffs_atime;
        !           285:        vap->va_atime.tv_nsec = ip->i_ffs_atimensec;
        !           286:        vap->va_mtime.tv_sec = ip->i_ffs_mtime;
        !           287:        vap->va_mtime.tv_nsec = ip->i_ffs_mtimensec;
        !           288:        vap->va_ctime.tv_sec = ip->i_ffs_ctime;
        !           289:        vap->va_ctime.tv_nsec = ip->i_ffs_ctimensec;
        !           290:        vap->va_flags = ip->i_ffs_flags;
        !           291:        vap->va_gen = ip->i_ffs_gen;
1.1       mycroft   292:        /* this doesn't belong here */
                    293:        if (vp->v_type == VBLK)
                    294:                vap->va_blocksize = BLKDEV_IOSIZE;
                    295:        else if (vp->v_type == VCHR)
                    296:                vap->va_blocksize = MAXBSIZE;
                    297:        else
                    298:                vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
1.26    ! bouyer    299:        vap->va_bytes = dbtob(ip->i_ffs_blocks);
1.1       mycroft   300:        vap->va_type = vp->v_type;
                    301:        vap->va_filerev = ip->i_modrev;
                    302:        return (0);
                    303: }
                    304:
                    305: /*
                    306:  * Set attribute vnode op. called from several syscalls
                    307:  */
                    308: int
1.15      christos  309: ufs_setattr(v)
                    310:        void *v;
                    311: {
1.1       mycroft   312:        struct vop_setattr_args /* {
                    313:                struct vnode *a_vp;
                    314:                struct vattr *a_vap;
                    315:                struct ucred *a_cred;
                    316:                struct proc *a_p;
1.15      christos  317:        } */ *ap = v;
1.1       mycroft   318:        register struct vattr *vap = ap->a_vap;
                    319:        register struct vnode *vp = ap->a_vp;
                    320:        register struct inode *ip = VTOI(vp);
                    321:        register struct ucred *cred = ap->a_cred;
                    322:        register struct proc *p = ap->a_p;
                    323:        int error;
                    324:
                    325:        /*
                    326:         * Check for unsettable attributes.
                    327:         */
                    328:        if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
                    329:            (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
                    330:            (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
                    331:            ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
                    332:                return (EINVAL);
                    333:        }
                    334:        if (vap->va_flags != VNOVAL) {
1.26    ! bouyer    335:                if (cred->cr_uid != ip->i_ffs_uid &&
1.1       mycroft   336:                    (error = suser(cred, &p->p_acflag)))
                    337:                        return (error);
                    338:                if (cred->cr_uid == 0) {
1.26    ! bouyer    339:                        if ((ip->i_ffs_flags & (SF_IMMUTABLE | SF_APPEND)) &&
1.1       mycroft   340:                            securelevel > 0)
                    341:                                return (EPERM);
1.26    ! bouyer    342:                        ip->i_ffs_flags = vap->va_flags;
1.1       mycroft   343:                } else {
1.26    ! bouyer    344:                        if (ip->i_ffs_flags & (SF_IMMUTABLE | SF_APPEND))
1.24      mikel     345:                                return (EPERM);
1.26    ! bouyer    346:                        if ((ip->i_ffs_flags & SF_SETTABLE) !=
1.24      mikel     347:                            (vap->va_flags & SF_SETTABLE))
1.1       mycroft   348:                                return (EPERM);
1.26    ! bouyer    349:                        ip->i_ffs_flags &= SF_SETTABLE;
        !           350:                        ip->i_ffs_flags |= (vap->va_flags & UF_SETTABLE);
1.1       mycroft   351:                }
                    352:                ip->i_flag |= IN_CHANGE;
                    353:                if (vap->va_flags & (IMMUTABLE | APPEND))
                    354:                        return (0);
                    355:        }
1.26    ! bouyer    356:        if (ip->i_ffs_flags & (IMMUTABLE | APPEND))
1.1       mycroft   357:                return (EPERM);
                    358:        /*
                    359:         * Go through the fields and update iff not VNOVAL.
                    360:         */
1.15      christos  361:        if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
                    362:                error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
                    363:                if (error)
1.1       mycroft   364:                        return (error);
1.15      christos  365:        }
1.1       mycroft   366:        if (vap->va_size != VNOVAL) {
                    367:                if (vp->v_type == VDIR)
                    368:                        return (EISDIR);
1.15      christos  369:                error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p);
                    370:                if (error)
1.1       mycroft   371:                        return (error);
                    372:        }
                    373:        ip = VTOI(vp);
1.12      jtc       374:        if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
1.26    ! bouyer    375:                if (cred->cr_uid != ip->i_ffs_uid &&
1.1       mycroft   376:                    (error = suser(cred, &p->p_acflag)) &&
                    377:                    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
                    378:                    (error = VOP_ACCESS(vp, VWRITE, cred, p))))
                    379:                        return (error);
1.12      jtc       380:                if (vap->va_atime.tv_sec != VNOVAL)
1.22      tls       381:                        if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
                    382:                                ip->i_flag |= IN_ACCESS;
1.12      jtc       383:                if (vap->va_mtime.tv_sec != VNOVAL)
1.1       mycroft   384:                        ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.18      mycroft   385:                error = VOP_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 1);
1.15      christos  386:                if (error)
1.1       mycroft   387:                        return (error);
                    388:        }
                    389:        error = 0;
                    390:        if (vap->va_mode != (mode_t)VNOVAL)
                    391:                error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
                    392:        return (error);
                    393: }
                    394:
                    395: /*
                    396:  * Change the mode on a file.
                    397:  * Inode must be locked before calling.
                    398:  */
                    399: static int
                    400: ufs_chmod(vp, mode, cred, p)
                    401:        register struct vnode *vp;
                    402:        register int mode;
                    403:        register struct ucred *cred;
                    404:        struct proc *p;
                    405: {
                    406:        register struct inode *ip = VTOI(vp);
                    407:        int error;
                    408:
1.26    ! bouyer    409:        if (cred->cr_uid != ip->i_ffs_uid &&
1.1       mycroft   410:            (error = suser(cred, &p->p_acflag)))
                    411:                return (error);
                    412:        if (cred->cr_uid) {
                    413:                if (vp->v_type != VDIR && (mode & S_ISTXT))
                    414:                        return (EFTYPE);
1.26    ! bouyer    415:                if (!groupmember(ip->i_ffs_gid, cred) && (mode & ISGID))
1.1       mycroft   416:                        return (EPERM);
                    417:        }
1.26    ! bouyer    418:        ip->i_ffs_mode &= ~ALLPERMS;
        !           419:        ip->i_ffs_mode |= (mode & ALLPERMS);
1.1       mycroft   420:        ip->i_flag |= IN_CHANGE;
1.26    ! bouyer    421:        if ((vp->v_flag & VTEXT) && (ip->i_ffs_mode & S_ISTXT) == 0)
1.1       mycroft   422:                (void) vnode_pager_uncache(vp);
                    423:        return (0);
                    424: }
                    425:
                    426: /*
                    427:  * Perform chown operation on inode ip;
                    428:  * inode must be locked prior to call.
                    429:  */
                    430: static int
                    431: ufs_chown(vp, uid, gid, cred, p)
                    432:        register struct vnode *vp;
                    433:        uid_t uid;
                    434:        gid_t gid;
                    435:        struct ucred *cred;
                    436:        struct proc *p;
                    437: {
                    438:        register struct inode *ip = VTOI(vp);
                    439:        uid_t ouid;
                    440:        gid_t ogid;
                    441:        int error = 0;
                    442: #ifdef QUOTA
                    443:        register int i;
                    444:        long change;
                    445: #endif
                    446:
                    447:        if (uid == (uid_t)VNOVAL)
1.26    ! bouyer    448:                uid = ip->i_ffs_uid;
1.1       mycroft   449:        if (gid == (gid_t)VNOVAL)
1.26    ! bouyer    450:                gid = ip->i_ffs_gid;
1.1       mycroft   451:        /*
                    452:         * If we don't own the file, are trying to change the owner
                    453:         * of the file, or are not a member of the target group,
                    454:         * the caller must be superuser or the call fails.
                    455:         */
1.26    ! bouyer    456:        if ((cred->cr_uid != ip->i_ffs_uid || uid != ip->i_ffs_uid ||
        !           457:            (gid != ip->i_ffs_gid && !groupmember((gid_t)gid, cred))) &&
1.1       mycroft   458:            (error = suser(cred, &p->p_acflag)))
                    459:                return (error);
1.26    ! bouyer    460:        ogid = ip->i_ffs_gid;
        !           461:        ouid = ip->i_ffs_uid;
1.1       mycroft   462: #ifdef QUOTA
1.15      christos  463:        if ((error = getinoquota(ip)) != 0)
1.1       mycroft   464:                return (error);
                    465:        if (ouid == uid) {
                    466:                dqrele(vp, ip->i_dquot[USRQUOTA]);
                    467:                ip->i_dquot[USRQUOTA] = NODQUOT;
                    468:        }
                    469:        if (ogid == gid) {
                    470:                dqrele(vp, ip->i_dquot[GRPQUOTA]);
                    471:                ip->i_dquot[GRPQUOTA] = NODQUOT;
                    472:        }
1.26    ! bouyer    473:        change = ip->i_ffs_blocks;
1.1       mycroft   474:        (void) chkdq(ip, -change, cred, CHOWN);
                    475:        (void) chkiq(ip, -1, cred, CHOWN);
                    476:        for (i = 0; i < MAXQUOTAS; i++) {
                    477:                dqrele(vp, ip->i_dquot[i]);
                    478:                ip->i_dquot[i] = NODQUOT;
                    479:        }
                    480: #endif
1.26    ! bouyer    481:        ip->i_ffs_gid = gid;
        !           482:        ip->i_ffs_uid = uid;
1.1       mycroft   483: #ifdef QUOTA
                    484:        if ((error = getinoquota(ip)) == 0) {
                    485:                if (ouid == uid) {
                    486:                        dqrele(vp, ip->i_dquot[USRQUOTA]);
                    487:                        ip->i_dquot[USRQUOTA] = NODQUOT;
                    488:                }
                    489:                if (ogid == gid) {
                    490:                        dqrele(vp, ip->i_dquot[GRPQUOTA]);
                    491:                        ip->i_dquot[GRPQUOTA] = NODQUOT;
                    492:                }
                    493:                if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
                    494:                        if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
                    495:                                goto good;
                    496:                        else
                    497:                                (void) chkdq(ip, -change, cred, CHOWN|FORCE);
                    498:                }
                    499:                for (i = 0; i < MAXQUOTAS; i++) {
                    500:                        dqrele(vp, ip->i_dquot[i]);
                    501:                        ip->i_dquot[i] = NODQUOT;
                    502:                }
                    503:        }
1.26    ! bouyer    504:        ip->i_ffs_gid = ogid;
        !           505:        ip->i_ffs_uid = ouid;
1.1       mycroft   506:        if (getinoquota(ip) == 0) {
                    507:                if (ouid == uid) {
                    508:                        dqrele(vp, ip->i_dquot[USRQUOTA]);
                    509:                        ip->i_dquot[USRQUOTA] = NODQUOT;
                    510:                }
                    511:                if (ogid == gid) {
                    512:                        dqrele(vp, ip->i_dquot[GRPQUOTA]);
                    513:                        ip->i_dquot[GRPQUOTA] = NODQUOT;
                    514:                }
                    515:                (void) chkdq(ip, change, cred, FORCE|CHOWN);
                    516:                (void) chkiq(ip, 1, cred, FORCE|CHOWN);
                    517:                (void) getinoquota(ip);
                    518:        }
                    519:        return (error);
                    520: good:
                    521:        if (getinoquota(ip))
                    522:                panic("chown: lost quota");
                    523: #endif /* QUOTA */
                    524:        if (ouid != uid || ogid != gid)
                    525:                ip->i_flag |= IN_CHANGE;
                    526:        if (ouid != uid && cred->cr_uid != 0)
1.26    ! bouyer    527:                ip->i_ffs_mode &= ~ISUID;
1.1       mycroft   528:        if (ogid != gid && cred->cr_uid != 0)
1.26    ! bouyer    529:                ip->i_ffs_mode &= ~ISGID;
1.1       mycroft   530:        return (0);
                    531: }
                    532:
                    533: /* ARGSUSED */
                    534: int
1.15      christos  535: ufs_ioctl(v)
                    536:        void *v;
                    537: {
                    538: #if 0
1.1       mycroft   539:        struct vop_ioctl_args /* {
                    540:                struct vnode *a_vp;
1.5       cgd       541:                u_long a_command;
1.1       mycroft   542:                caddr_t  a_data;
                    543:                int  a_fflag;
                    544:                struct ucred *a_cred;
                    545:                struct proc *a_p;
1.15      christos  546:        } */ *ap = v;
                    547: #endif
1.1       mycroft   548:        return (ENOTTY);
                    549: }
                    550:
                    551: /*
                    552:  * Mmap a file
                    553:  *
                    554:  * NB Currently unsupported.
                    555:  */
                    556: /* ARGSUSED */
                    557: int
1.15      christos  558: ufs_mmap(v)
                    559:        void *v;
                    560: {
                    561: #if 0
1.1       mycroft   562:        struct vop_mmap_args /* {
                    563:                struct vnode *a_vp;
                    564:                int  a_fflags;
                    565:                struct ucred *a_cred;
                    566:                struct proc *a_p;
1.15      christos  567:        } */ *ap = v;
                    568: #endif
1.1       mycroft   569:
                    570:        return (EINVAL);
                    571: }
                    572:
                    573: int
1.15      christos  574: ufs_remove(v)
                    575:        void *v;
                    576: {
1.1       mycroft   577:        struct vop_remove_args /* {
                    578:                struct vnode *a_dvp;
                    579:                struct vnode *a_vp;
                    580:                struct componentname *a_cnp;
1.15      christos  581:        } */ *ap = v;
1.1       mycroft   582:        register struct inode *ip;
                    583:        register struct vnode *vp = ap->a_vp;
                    584:        register struct vnode *dvp = ap->a_dvp;
                    585:        int error;
                    586:
1.14      mycroft   587:        if (vp->v_type == VDIR) {
                    588:                error = EISDIR;
                    589:                goto out;
                    590:        }
1.1       mycroft   591:        ip = VTOI(vp);
1.26    ! bouyer    592:        if ((ip->i_ffs_flags & (IMMUTABLE | APPEND)) ||
        !           593:            (VTOI(dvp)->i_ffs_flags & APPEND)) {
1.1       mycroft   594:                error = EPERM;
                    595:                goto out;
                    596:        }
1.26    ! bouyer    597:     error = ufs_dirremove(dvp, ap->a_cnp);
        !           598:     if (error == 0) {
        !           599:                ip->i_ffs_nlink--;
1.1       mycroft   600:                ip->i_flag |= IN_CHANGE;
                    601:        }
                    602: out:
                    603:        if (dvp == vp)
                    604:                vrele(vp);
                    605:        else
                    606:                vput(vp);
                    607:        vput(dvp);
                    608:        return (error);
                    609: }
                    610:
                    611: /*
                    612:  * link vnode call
                    613:  */
                    614: int
1.15      christos  615: ufs_link(v)
                    616:        void *v;
                    617: {
1.1       mycroft   618:        struct vop_link_args /* {
1.14      mycroft   619:                struct vnode *a_dvp;
1.1       mycroft   620:                struct vnode *a_vp;
                    621:                struct componentname *a_cnp;
1.15      christos  622:        } */ *ap = v;
1.16      christos  623:        register struct vnode *dvp = ap->a_dvp;
1.1       mycroft   624:        register struct vnode *vp = ap->a_vp;
                    625:        register struct componentname *cnp = ap->a_cnp;
                    626:        register struct inode *ip;
1.18      mycroft   627:        struct timespec ts;
1.1       mycroft   628:        int error;
                    629:
                    630: #ifdef DIAGNOSTIC
                    631:        if ((cnp->cn_flags & HASBUF) == 0)
                    632:                panic("ufs_link: no name");
                    633: #endif
1.14      mycroft   634:        if (vp->v_type == VDIR) {
                    635:                VOP_ABORTOP(dvp, cnp);
1.23      mikel     636:                error = EPERM;
1.14      mycroft   637:                goto out2;
                    638:        }
                    639:        if (dvp->v_mount != vp->v_mount) {
                    640:                VOP_ABORTOP(dvp, cnp);
1.1       mycroft   641:                error = EXDEV;
                    642:                goto out2;
                    643:        }
1.14      mycroft   644:        if (dvp != vp && (error = VOP_LOCK(vp))) {
                    645:                VOP_ABORTOP(dvp, cnp);
1.1       mycroft   646:                goto out2;
                    647:        }
1.14      mycroft   648:        ip = VTOI(vp);
1.26    ! bouyer    649:        if ((nlink_t)ip->i_ffs_nlink >= LINK_MAX) {
1.14      mycroft   650:                VOP_ABORTOP(dvp, cnp);
1.1       mycroft   651:                error = EMLINK;
                    652:                goto out1;
                    653:        }
1.26    ! bouyer    654:        if (ip->i_ffs_flags & (IMMUTABLE | APPEND)) {
1.14      mycroft   655:                VOP_ABORTOP(dvp, cnp);
1.1       mycroft   656:                error = EPERM;
                    657:                goto out1;
                    658:        }
1.26    ! bouyer    659:        ip->i_ffs_nlink++;
1.1       mycroft   660:        ip->i_flag |= IN_CHANGE;
1.18      mycroft   661:        TIMEVAL_TO_TIMESPEC(&time, &ts);
                    662:        error = VOP_UPDATE(vp, &ts, &ts, 1);
1.1       mycroft   663:        if (!error)
1.14      mycroft   664:                error = ufs_direnter(ip, dvp, cnp);
1.1       mycroft   665:        if (error) {
1.26    ! bouyer    666:                ip->i_ffs_nlink--;
1.1       mycroft   667:                ip->i_flag |= IN_CHANGE;
                    668:        }
                    669:        FREE(cnp->cn_pnbuf, M_NAMEI);
                    670: out1:
1.14      mycroft   671:        if (dvp != vp)
                    672:                VOP_UNLOCK(vp);
1.1       mycroft   673: out2:
1.14      mycroft   674:        vput(dvp);
1.1       mycroft   675:        return (error);
                    676: }
                    677:
                    678: /*
1.6       mycroft   679:  * whiteout vnode call
                    680:  */
                    681: int
1.15      christos  682: ufs_whiteout(v)
                    683:        void *v;
                    684: {
1.6       mycroft   685:        struct vop_whiteout_args /* {
                    686:                struct vnode *a_dvp;
                    687:                struct componentname *a_cnp;
                    688:                int a_flags;
1.15      christos  689:        } */ *ap = v;
1.6       mycroft   690:        struct vnode *dvp = ap->a_dvp;
                    691:        struct componentname *cnp = ap->a_cnp;
                    692:        struct direct newdir;
1.15      christos  693:        int error = 0;
1.6       mycroft   694:
                    695:        switch (ap->a_flags) {
                    696:        case LOOKUP:
                    697:                /* 4.4 format directories support whiteout operations */
                    698:                if (dvp->v_mount->mnt_maxsymlinklen > 0)
                    699:                        return (0);
                    700:                return (EOPNOTSUPP);
                    701:
                    702:        case CREATE:
                    703:                /* create a new directory whiteout */
                    704: #ifdef DIAGNOSTIC
                    705:                if ((cnp->cn_flags & SAVENAME) == 0)
                    706:                        panic("ufs_whiteout: missing name");
                    707:                if (dvp->v_mount->mnt_maxsymlinklen <= 0)
                    708:                        panic("ufs_whiteout: old format filesystem");
                    709: #endif
                    710:
                    711:                newdir.d_ino = WINO;
                    712:                newdir.d_namlen = cnp->cn_namelen;
                    713:                bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1);
                    714:                newdir.d_type = DT_WHT;
                    715:                error = ufs_direnter2(dvp, &newdir, cnp->cn_cred, cnp->cn_proc);
                    716:                break;
                    717:
                    718:        case DELETE:
                    719:                /* remove an existing directory whiteout */
                    720: #ifdef DIAGNOSTIC
                    721:                if (dvp->v_mount->mnt_maxsymlinklen <= 0)
                    722:                        panic("ufs_whiteout: old format filesystem");
                    723: #endif
                    724:
                    725:                cnp->cn_flags &= ~DOWHITEOUT;
                    726:                error = ufs_dirremove(dvp, cnp);
                    727:                break;
                    728:        }
                    729:        if (cnp->cn_flags & HASBUF) {
                    730:                FREE(cnp->cn_pnbuf, M_NAMEI);
                    731:                cnp->cn_flags &= ~HASBUF;
                    732:        }
                    733:        return (error);
                    734: }
                    735:
                    736:
                    737: /*
1.1       mycroft   738:  * Rename system call.
                    739:  *     rename("foo", "bar");
                    740:  * is essentially
                    741:  *     unlink("bar");
                    742:  *     link("foo", "bar");
                    743:  *     unlink("foo");
                    744:  * but ``atomically''.  Can't do full commit without saving state in the
                    745:  * inode on disk which isn't feasible at this time.  Best we can do is
                    746:  * always guarantee the target exists.
                    747:  *
                    748:  * Basic algorithm is:
                    749:  *
                    750:  * 1) Bump link count on source while we're linking it to the
                    751:  *    target.  This also ensure the inode won't be deleted out
                    752:  *    from underneath us while we work (it may be truncated by
                    753:  *    a concurrent `trunc' or `open' for creation).
                    754:  * 2) Link source to destination.  If destination already exists,
                    755:  *    delete it first.
                    756:  * 3) Unlink source reference to inode if still around. If a
                    757:  *    directory was moved and the parent of the destination
                    758:  *    is different from the source, patch the ".." entry in the
                    759:  *    directory.
                    760:  */
                    761: int
1.15      christos  762: ufs_rename(v)
                    763:        void *v;
                    764: {
1.1       mycroft   765:        struct vop_rename_args  /* {
                    766:                struct vnode *a_fdvp;
                    767:                struct vnode *a_fvp;
                    768:                struct componentname *a_fcnp;
                    769:                struct vnode *a_tdvp;
                    770:                struct vnode *a_tvp;
                    771:                struct componentname *a_tcnp;
1.15      christos  772:        } */ *ap = v;
1.1       mycroft   773:        struct vnode *tvp = ap->a_tvp;
                    774:        register struct vnode *tdvp = ap->a_tdvp;
                    775:        struct vnode *fvp = ap->a_fvp;
                    776:        register struct vnode *fdvp = ap->a_fdvp;
                    777:        register struct componentname *tcnp = ap->a_tcnp;
                    778:        register struct componentname *fcnp = ap->a_fcnp;
                    779:        register struct inode *ip, *xp, *dp;
                    780:        struct dirtemplate dirbuf;
1.18      mycroft   781:        struct timespec ts;
1.1       mycroft   782:        int doingdirectory = 0, oldparent = 0, newparent = 0;
                    783:        int error = 0;
                    784:        u_char namlen;
                    785:
                    786: #ifdef DIAGNOSTIC
                    787:        if ((tcnp->cn_flags & HASBUF) == 0 ||
                    788:            (fcnp->cn_flags & HASBUF) == 0)
                    789:                panic("ufs_rename: no name");
                    790: #endif
                    791:        /*
                    792:         * Check for cross-device rename.
                    793:         */
                    794:        if ((fvp->v_mount != tdvp->v_mount) ||
                    795:            (tvp && (fvp->v_mount != tvp->v_mount))) {
                    796:                error = EXDEV;
                    797: abortit:
                    798:                VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
                    799:                if (tdvp == tvp)
                    800:                        vrele(tdvp);
                    801:                else
                    802:                        vput(tdvp);
                    803:                if (tvp)
                    804:                        vput(tvp);
                    805:                VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
                    806:                vrele(fdvp);
                    807:                vrele(fvp);
                    808:                return (error);
                    809:        }
                    810:
                    811:        /*
                    812:         * Check if just deleting a link name.
                    813:         */
1.26    ! bouyer    814:        if (tvp && ((VTOI(tvp)->i_ffs_flags & (IMMUTABLE | APPEND)) ||
        !           815:            (VTOI(tdvp)->i_ffs_flags & APPEND))) {
1.1       mycroft   816:                error = EPERM;
                    817:                goto abortit;
                    818:        }
                    819:        if (fvp == tvp) {
                    820:                if (fvp->v_type == VDIR) {
                    821:                        error = EINVAL;
                    822:                        goto abortit;
                    823:                }
1.9       cgd       824:
                    825:                /* Release destination completely. */
                    826:                VOP_ABORTOP(tdvp, tcnp);
                    827:                vput(tdvp);
                    828:                vput(tvp);
                    829:
                    830:                /* Delete source. */
1.1       mycroft   831:                vrele(fdvp);
                    832:                vrele(fvp);
1.9       cgd       833:                fcnp->cn_flags &= ~MODMASK;
                    834:                fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
                    835:                if ((fcnp->cn_flags & SAVESTART) == 0)
1.1       mycroft   836:                        panic("ufs_rename: lost from startdir");
1.9       cgd       837:                fcnp->cn_nameiop = DELETE;
                    838:                (void) relookup(fdvp, &fvp, fcnp);
                    839:                return (VOP_REMOVE(fdvp, fvp, fcnp));
1.1       mycroft   840:        }
1.15      christos  841:        if ((error = VOP_LOCK(fvp)) != 0)
1.1       mycroft   842:                goto abortit;
                    843:        dp = VTOI(fdvp);
                    844:        ip = VTOI(fvp);
1.26    ! bouyer    845:        if ((ip->i_ffs_flags & (IMMUTABLE | APPEND)) ||
        !           846:                (dp->i_ffs_flags & APPEND)) {
1.1       mycroft   847:                VOP_UNLOCK(fvp);
                    848:                error = EPERM;
                    849:                goto abortit;
                    850:        }
1.26    ! bouyer    851:        if ((ip->i_ffs_mode & IFMT) == IFDIR) {
1.1       mycroft   852:                /*
                    853:                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                    854:                 */
                    855:                if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
                    856:                    dp == ip || (fcnp->cn_flags&ISDOTDOT) ||
                    857:                    (ip->i_flag & IN_RENAME)) {
                    858:                        VOP_UNLOCK(fvp);
                    859:                        error = EINVAL;
                    860:                        goto abortit;
                    861:                }
                    862:                ip->i_flag |= IN_RENAME;
                    863:                oldparent = dp->i_number;
                    864:                doingdirectory++;
                    865:        }
                    866:        vrele(fdvp);
                    867:
                    868:        /*
                    869:         * When the target exists, both the directory
                    870:         * and target vnodes are returned locked.
                    871:         */
                    872:        dp = VTOI(tdvp);
                    873:        xp = NULL;
                    874:        if (tvp)
                    875:                xp = VTOI(tvp);
                    876:
                    877:        /*
                    878:         * 1) Bump link count while we're moving stuff
                    879:         *    around.  If we crash somewhere before
                    880:         *    completing our work, the link count
                    881:         *    may be wrong, but correctable.
                    882:         */
1.26    ! bouyer    883:        ip->i_ffs_nlink++;
1.1       mycroft   884:        ip->i_flag |= IN_CHANGE;
1.18      mycroft   885:        TIMEVAL_TO_TIMESPEC(&time, &ts);
                    886:        if ((error = VOP_UPDATE(fvp, &ts, &ts, 1)) != 0) {
1.1       mycroft   887:                VOP_UNLOCK(fvp);
                    888:                goto bad;
                    889:        }
                    890:
                    891:        /*
                    892:         * If ".." must be changed (ie the directory gets a new
                    893:         * parent) then the source directory must not be in the
                    894:         * directory heirarchy above the target, as this would
                    895:         * orphan everything below the source directory. Also
                    896:         * the user must have write permission in the source so
                    897:         * as to be able to change "..". We must repeat the call
                    898:         * to namei, as the parent directory is unlocked by the
                    899:         * call to checkpath().
                    900:         */
                    901:        error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
                    902:        VOP_UNLOCK(fvp);
                    903:        if (oldparent != dp->i_number)
                    904:                newparent = dp->i_number;
                    905:        if (doingdirectory && newparent) {
                    906:                if (error)      /* write access check above */
                    907:                        goto bad;
                    908:                if (xp != NULL)
                    909:                        vput(tvp);
1.15      christos  910:                if ((error = ufs_checkpath(ip, dp, tcnp->cn_cred)) != 0)
1.1       mycroft   911:                        goto out;
                    912:                if ((tcnp->cn_flags & SAVESTART) == 0)
                    913:                        panic("ufs_rename: lost to startdir");
1.15      christos  914:                if ((error = relookup(tdvp, &tvp, tcnp)) != 0)
1.1       mycroft   915:                        goto out;
                    916:                dp = VTOI(tdvp);
                    917:                xp = NULL;
                    918:                if (tvp)
                    919:                        xp = VTOI(tvp);
                    920:        }
                    921:        /*
                    922:         * 2) If target doesn't exist, link the target
                    923:         *    to the source and unlink the source.
                    924:         *    Otherwise, rewrite the target directory
                    925:         *    entry to reference the source inode and
                    926:         *    expunge the original entry's existence.
                    927:         */
                    928:        if (xp == NULL) {
                    929:                if (dp->i_dev != ip->i_dev)
                    930:                        panic("rename: EXDEV");
                    931:                /*
                    932:                 * Account for ".." in new directory.
                    933:                 * When source and destination have the same
                    934:                 * parent we don't fool with the link count.
                    935:                 */
                    936:                if (doingdirectory && newparent) {
1.26    ! bouyer    937:                        if ((nlink_t)dp->i_ffs_nlink >= LINK_MAX) {
1.1       mycroft   938:                                error = EMLINK;
                    939:                                goto bad;
                    940:                        }
1.26    ! bouyer    941:                        dp->i_ffs_nlink++;
1.1       mycroft   942:                        dp->i_flag |= IN_CHANGE;
1.18      mycroft   943:                        if ((error = VOP_UPDATE(tdvp, &ts, &ts, 1)) != 0)
1.1       mycroft   944:                                goto bad;
                    945:                }
1.15      christos  946:                if ((error = ufs_direnter(ip, tdvp, tcnp)) != 0) {
1.1       mycroft   947:                        if (doingdirectory && newparent) {
1.26    ! bouyer    948:                                dp->i_ffs_nlink--;
1.1       mycroft   949:                                dp->i_flag |= IN_CHANGE;
1.18      mycroft   950:                                (void)VOP_UPDATE(tdvp, &ts, &ts, 1);
1.1       mycroft   951:                        }
                    952:                        goto bad;
                    953:                }
                    954:                vput(tdvp);
                    955:        } else {
                    956:                if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
                    957:                        panic("rename: EXDEV");
                    958:                /*
                    959:                 * Short circuit rename(foo, foo).
                    960:                 */
                    961:                if (xp->i_number == ip->i_number)
                    962:                        panic("rename: same file");
                    963:                /*
                    964:                 * If the parent directory is "sticky", then the user must
                    965:                 * own the parent directory, or the destination of the rename,
                    966:                 * otherwise the destination may not be changed (except by
                    967:                 * root). This implements append-only directories.
                    968:                 */
1.26    ! bouyer    969:                if ((dp->i_ffs_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
        !           970:                    tcnp->cn_cred->cr_uid != dp->i_ffs_uid &&
        !           971:                    xp->i_ffs_uid != tcnp->cn_cred->cr_uid) {
1.1       mycroft   972:                        error = EPERM;
                    973:                        goto bad;
                    974:                }
                    975:                /*
                    976:                 * Target must be empty if a directory and have no links
                    977:                 * to it. Also, ensure source and target are compatible
                    978:                 * (both directories, or both not directories).
                    979:                 */
1.26    ! bouyer    980:                if ((xp->i_ffs_mode & IFMT) == IFDIR) {
1.1       mycroft   981:                        if (!ufs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
1.26    ! bouyer    982:                                xp->i_ffs_nlink > 2) {
1.1       mycroft   983:                                error = ENOTEMPTY;
                    984:                                goto bad;
                    985:                        }
                    986:                        if (!doingdirectory) {
                    987:                                error = ENOTDIR;
                    988:                                goto bad;
                    989:                        }
                    990:                        cache_purge(tdvp);
                    991:                } else if (doingdirectory) {
                    992:                        error = EISDIR;
                    993:                        goto bad;
                    994:                }
1.15      christos  995:                if ((error = ufs_dirrewrite(dp, ip, tcnp)) != 0)
1.1       mycroft   996:                        goto bad;
                    997:                /*
                    998:                 * If the target directory is in the same
                    999:                 * directory as the source directory,
                   1000:                 * decrement the link count on the parent
                   1001:                 * of the target directory.
                   1002:                 */
                   1003:                 if (doingdirectory && !newparent) {
1.26    ! bouyer   1004:                        dp->i_ffs_nlink--;
1.1       mycroft  1005:                        dp->i_flag |= IN_CHANGE;
                   1006:                }
                   1007:                vput(tdvp);
                   1008:                /*
                   1009:                 * Adjust the link count of the target to
                   1010:                 * reflect the dirrewrite above.  If this is
                   1011:                 * a directory it is empty and there are
                   1012:                 * no links to it, so we can squash the inode and
                   1013:                 * any space associated with it.  We disallowed
                   1014:                 * renaming over top of a directory with links to
                   1015:                 * it above, as the remaining link would point to
                   1016:                 * a directory without "." or ".." entries.
                   1017:                 */
1.26    ! bouyer   1018:                xp->i_ffs_nlink--;
1.1       mycroft  1019:                if (doingdirectory) {
1.26    ! bouyer   1020:                        if (--xp->i_ffs_nlink != 0)
1.1       mycroft  1021:                                panic("rename: linked directory");
                   1022:                        error = VOP_TRUNCATE(tvp, (off_t)0, IO_SYNC,
                   1023:                            tcnp->cn_cred, tcnp->cn_proc);
                   1024:                }
                   1025:                xp->i_flag |= IN_CHANGE;
                   1026:                vput(tvp);
                   1027:                xp = NULL;
                   1028:        }
                   1029:
                   1030:        /*
                   1031:         * 3) Unlink the source.
                   1032:         */
                   1033:        fcnp->cn_flags &= ~MODMASK;
                   1034:        fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
                   1035:        if ((fcnp->cn_flags & SAVESTART) == 0)
                   1036:                panic("ufs_rename: lost from startdir");
                   1037:        (void) relookup(fdvp, &fvp, fcnp);
                   1038:        if (fvp != NULL) {
                   1039:                xp = VTOI(fvp);
                   1040:                dp = VTOI(fdvp);
                   1041:        } else {
                   1042:                /*
                   1043:                 * From name has disappeared.
                   1044:                 */
                   1045:                if (doingdirectory)
                   1046:                        panic("rename: lost dir entry");
                   1047:                vrele(ap->a_fvp);
                   1048:                return (0);
                   1049:        }
                   1050:        /*
                   1051:         * Ensure that the directory entry still exists and has not
                   1052:         * changed while the new name has been entered. If the source is
                   1053:         * a file then the entry may have been unlinked or renamed. In
                   1054:         * either case there is no further work to be done. If the source
                   1055:         * is a directory then it cannot have been rmdir'ed; its link
                   1056:         * count of three would cause a rmdir to fail with ENOTEMPTY.
                   1057:         * The IRENAME flag ensures that it cannot be moved by another
                   1058:         * rename.
                   1059:         */
                   1060:        if (xp != ip) {
                   1061:                if (doingdirectory)
                   1062:                        panic("rename: lost dir entry");
                   1063:        } else {
                   1064:                /*
                   1065:                 * If the source is a directory with a
                   1066:                 * new parent, the link count of the old
                   1067:                 * parent directory must be decremented
                   1068:                 * and ".." set to point to the new parent.
                   1069:                 */
                   1070:                if (doingdirectory && newparent) {
1.26    ! bouyer   1071:                        dp->i_ffs_nlink--;
1.1       mycroft  1072:                        dp->i_flag |= IN_CHANGE;
                   1073:                        error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
                   1074:                                sizeof (struct dirtemplate), (off_t)0,
                   1075:                                UIO_SYSSPACE, IO_NODELOCKED,
                   1076:                                tcnp->cn_cred, (int *)0, (struct proc *)0);
                   1077:                        if (error == 0) {
                   1078: #                              if (BYTE_ORDER == LITTLE_ENDIAN)
                   1079:                                        if (fvp->v_mount->mnt_maxsymlinklen <= 0)
                   1080:                                                namlen = dirbuf.dotdot_type;
                   1081:                                        else
                   1082:                                                namlen = dirbuf.dotdot_namlen;
                   1083: #                              else
                   1084:                                        namlen = dirbuf.dotdot_namlen;
                   1085: #                              endif
                   1086:                                if (namlen != 2 ||
                   1087:                                    dirbuf.dotdot_name[0] != '.' ||
                   1088:                                    dirbuf.dotdot_name[1] != '.') {
                   1089:                                        ufs_dirbad(xp, (doff_t)12,
                   1090:                                            "rename: mangled dir");
                   1091:                                } else {
                   1092:                                        dirbuf.dotdot_ino = newparent;
                   1093:                                        (void) vn_rdwr(UIO_WRITE, fvp,
                   1094:                                            (caddr_t)&dirbuf,
                   1095:                                            sizeof (struct dirtemplate),
                   1096:                                            (off_t)0, UIO_SYSSPACE,
                   1097:                                            IO_NODELOCKED|IO_SYNC,
                   1098:                                            tcnp->cn_cred, (int *)0,
                   1099:                                            (struct proc *)0);
                   1100:                                        cache_purge(fdvp);
                   1101:                                }
                   1102:                        }
                   1103:                }
                   1104:                error = ufs_dirremove(fdvp, fcnp);
                   1105:                if (!error) {
1.26    ! bouyer   1106:                        xp->i_ffs_nlink--;
1.1       mycroft  1107:                        xp->i_flag |= IN_CHANGE;
                   1108:                }
                   1109:                xp->i_flag &= ~IN_RENAME;
                   1110:        }
                   1111:        if (dp)
                   1112:                vput(fdvp);
                   1113:        if (xp)
                   1114:                vput(fvp);
                   1115:        vrele(ap->a_fvp);
                   1116:        return (error);
                   1117:
                   1118: bad:
                   1119:        if (xp)
                   1120:                vput(ITOV(xp));
                   1121:        vput(ITOV(dp));
                   1122: out:
1.8       mycroft  1123:        if (doingdirectory)
                   1124:                ip->i_flag &= ~IN_RENAME;
1.1       mycroft  1125:        if (VOP_LOCK(fvp) == 0) {
1.26    ! bouyer   1126:                ip->i_ffs_nlink--;
1.1       mycroft  1127:                ip->i_flag |= IN_CHANGE;
                   1128:                vput(fvp);
                   1129:        } else
                   1130:                vrele(fvp);
                   1131:        return (error);
                   1132: }
                   1133:
                   1134: /*
                   1135:  * A virgin directory (no blushing please).
                   1136:  */
                   1137: static struct dirtemplate mastertemplate = {
                   1138:        0, 12, DT_DIR, 1, ".",
                   1139:        0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
                   1140: };
                   1141: static struct odirtemplate omastertemplate = {
                   1142:        0, 12, 1, ".",
                   1143:        0, DIRBLKSIZ - 12, 2, ".."
                   1144: };
                   1145:
                   1146: /*
                   1147:  * Mkdir system call
                   1148:  */
                   1149: int
1.15      christos 1150: ufs_mkdir(v)
                   1151:        void *v;
                   1152: {
1.1       mycroft  1153:        struct vop_mkdir_args /* {
                   1154:                struct vnode *a_dvp;
                   1155:                struct vnode **a_vpp;
                   1156:                struct componentname *a_cnp;
                   1157:                struct vattr *a_vap;
1.15      christos 1158:        } */ *ap = v;
1.1       mycroft  1159:        register struct vnode *dvp = ap->a_dvp;
                   1160:        register struct vattr *vap = ap->a_vap;
                   1161:        register struct componentname *cnp = ap->a_cnp;
                   1162:        register struct inode *ip, *dp;
                   1163:        struct vnode *tvp;
                   1164:        struct dirtemplate dirtemplate, *dtp;
1.18      mycroft  1165:        struct timespec ts;
1.1       mycroft  1166:        int error, dmode;
                   1167:
                   1168: #ifdef DIAGNOSTIC
                   1169:        if ((cnp->cn_flags & HASBUF) == 0)
                   1170:                panic("ufs_mkdir: no name");
                   1171: #endif
                   1172:        dp = VTOI(dvp);
1.26    ! bouyer   1173:        if ((nlink_t)dp->i_ffs_nlink >= LINK_MAX) {
1.1       mycroft  1174:                error = EMLINK;
                   1175:                goto out;
                   1176:        }
1.25      mycroft  1177:        dmode = vap->va_mode & ACCESSPERMS;
1.1       mycroft  1178:        dmode |= IFDIR;
                   1179:        /*
                   1180:         * Must simulate part of ufs_makeinode here to acquire the inode,
                   1181:         * but not have it entered in the parent directory. The entry is
                   1182:         * made later after writing "." and ".." entries.
                   1183:         */
1.15      christos 1184:        if ((error = VOP_VALLOC(dvp, dmode, cnp->cn_cred, &tvp)) != 0)
1.1       mycroft  1185:                goto out;
                   1186:        ip = VTOI(tvp);
1.26    ! bouyer   1187:        ip->i_ffs_uid = cnp->cn_cred->cr_uid;
        !          1188:        ip->i_ffs_gid = dp->i_ffs_gid;
1.1       mycroft  1189: #ifdef QUOTA
                   1190:        if ((error = getinoquota(ip)) ||
                   1191:            (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
                   1192:                free(cnp->cn_pnbuf, M_NAMEI);
                   1193:                VOP_VFREE(tvp, ip->i_number, dmode);
                   1194:                vput(tvp);
                   1195:                vput(dvp);
                   1196:                return (error);
                   1197:        }
                   1198: #endif
                   1199:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1.26    ! bouyer   1200:        ip->i_ffs_mode = dmode;
1.1       mycroft  1201:        tvp->v_type = VDIR;     /* Rest init'd in getnewvnode(). */
1.26    ! bouyer   1202:        ip->i_ffs_nlink = 2;
1.6       mycroft  1203:        if (cnp->cn_flags & ISWHITEOUT)
1.26    ! bouyer   1204:                ip->i_ffs_flags |= UF_OPAQUE;
1.18      mycroft  1205:        TIMEVAL_TO_TIMESPEC(&time, &ts);
                   1206:        error = VOP_UPDATE(tvp, &ts, &ts, 1);
1.1       mycroft  1207:
                   1208:        /*
                   1209:         * Bump link count in parent directory
                   1210:         * to reflect work done below.  Should
                   1211:         * be done before reference is created
                   1212:         * so reparation is possible if we crash.
                   1213:         */
1.26    ! bouyer   1214:        dp->i_ffs_nlink++;
1.1       mycroft  1215:        dp->i_flag |= IN_CHANGE;
1.18      mycroft  1216:        if ((error = VOP_UPDATE(dvp, &ts, &ts, 1)) != 0)
1.1       mycroft  1217:                goto bad;
                   1218:
                   1219:        /* Initialize directory with "." and ".." from static template. */
                   1220:        if (dvp->v_mount->mnt_maxsymlinklen > 0)
                   1221:                dtp = &mastertemplate;
                   1222:        else
                   1223:                dtp = (struct dirtemplate *)&omastertemplate;
                   1224:        dirtemplate = *dtp;
                   1225:        dirtemplate.dot_ino = ip->i_number;
                   1226:        dirtemplate.dotdot_ino = dp->i_number;
                   1227:        error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
                   1228:            sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
                   1229:            IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0);
                   1230:        if (error) {
1.26    ! bouyer   1231:                dp->i_ffs_nlink--;
1.1       mycroft  1232:                dp->i_flag |= IN_CHANGE;
                   1233:                goto bad;
                   1234:        }
                   1235:        if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
                   1236:                panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
                   1237:        else {
1.26    ! bouyer   1238:                ip->i_ffs_size = DIRBLKSIZ;
1.1       mycroft  1239:                ip->i_flag |= IN_CHANGE;
                   1240:        }
                   1241:
                   1242:        /* Directory set up, now install it's entry in the parent directory. */
1.15      christos 1243:        if ((error = ufs_direnter(ip, dvp, cnp)) != 0) {
1.26    ! bouyer   1244:                dp->i_ffs_nlink--;
1.1       mycroft  1245:                dp->i_flag |= IN_CHANGE;
                   1246:        }
                   1247: bad:
                   1248:        /*
                   1249:         * No need to do an explicit VOP_TRUNCATE here, vrele will do this
                   1250:         * for us because we set the link count to 0.
                   1251:         */
                   1252:        if (error) {
1.26    ! bouyer   1253:                ip->i_ffs_nlink = 0;
1.1       mycroft  1254:                ip->i_flag |= IN_CHANGE;
                   1255:                vput(tvp);
                   1256:        } else
                   1257:                *ap->a_vpp = tvp;
                   1258: out:
                   1259:        FREE(cnp->cn_pnbuf, M_NAMEI);
                   1260:        vput(dvp);
                   1261:        return (error);
                   1262: }
                   1263:
                   1264: /*
                   1265:  * Rmdir system call.
                   1266:  */
                   1267: int
1.15      christos 1268: ufs_rmdir(v)
                   1269:        void *v;
                   1270: {
1.1       mycroft  1271:        struct vop_rmdir_args /* {
                   1272:                struct vnode *a_dvp;
                   1273:                struct vnode *a_vp;
                   1274:                struct componentname *a_cnp;
1.15      christos 1275:        } */ *ap = v;
1.1       mycroft  1276:        register struct vnode *vp = ap->a_vp;
                   1277:        register struct vnode *dvp = ap->a_dvp;
                   1278:        register struct componentname *cnp = ap->a_cnp;
                   1279:        register struct inode *ip, *dp;
                   1280:        int error;
                   1281:
                   1282:        ip = VTOI(vp);
                   1283:        dp = VTOI(dvp);
                   1284:        /*
                   1285:         * No rmdir "." please.
                   1286:         */
                   1287:        if (dp == ip) {
                   1288:                vrele(dvp);
                   1289:                vput(vp);
                   1290:                return (EINVAL);
                   1291:        }
                   1292:        /*
                   1293:         * Verify the directory is empty (and valid).
                   1294:         * (Rmdir ".." won't be valid since
                   1295:         *  ".." will contain a reference to
                   1296:         *  the current directory and thus be
                   1297:         *  non-empty.)
                   1298:         */
                   1299:        error = 0;
1.26    ! bouyer   1300:        if (ip->i_ffs_nlink != 2 ||
1.1       mycroft  1301:            !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
                   1302:                error = ENOTEMPTY;
                   1303:                goto out;
                   1304:        }
1.26    ! bouyer   1305:        if ((dp->i_ffs_flags & APPEND) ||
        !          1306:                (ip->i_ffs_flags & (IMMUTABLE | APPEND))) {
1.1       mycroft  1307:                error = EPERM;
                   1308:                goto out;
                   1309:        }
                   1310:        /*
                   1311:         * Delete reference to directory before purging
                   1312:         * inode.  If we crash in between, the directory
                   1313:         * will be reattached to lost+found,
                   1314:         */
1.15      christos 1315:        if ((error = ufs_dirremove(dvp, cnp)) != 0)
1.1       mycroft  1316:                goto out;
1.26    ! bouyer   1317:        dp->i_ffs_nlink--;
1.1       mycroft  1318:        dp->i_flag |= IN_CHANGE;
                   1319:        cache_purge(dvp);
                   1320:        vput(dvp);
                   1321:        dvp = NULL;
                   1322:        /*
                   1323:         * Truncate inode.  The only stuff left
                   1324:         * in the directory is "." and "..".  The
                   1325:         * "." reference is inconsequential since
                   1326:         * we're quashing it.  The ".." reference
                   1327:         * has already been adjusted above.  We've
                   1328:         * removed the "." reference and the reference
                   1329:         * in the parent directory, but there may be
                   1330:         * other hard links so decrement by 2 and
                   1331:         * worry about them later.
                   1332:         */
1.26    ! bouyer   1333:        ip->i_ffs_nlink -= 2;
1.1       mycroft  1334:        error = VOP_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred,
                   1335:            cnp->cn_proc);
                   1336:        cache_purge(ITOV(ip));
                   1337: out:
                   1338:        if (dvp)
                   1339:                vput(dvp);
                   1340:        vput(vp);
                   1341:        return (error);
                   1342: }
                   1343:
                   1344: /*
                   1345:  * symlink -- make a symbolic link
                   1346:  */
                   1347: int
1.15      christos 1348: ufs_symlink(v)
                   1349:        void *v;
                   1350: {
1.1       mycroft  1351:        struct vop_symlink_args /* {
                   1352:                struct vnode *a_dvp;
                   1353:                struct vnode **a_vpp;
                   1354:                struct componentname *a_cnp;
                   1355:                struct vattr *a_vap;
                   1356:                char *a_target;
1.15      christos 1357:        } */ *ap = v;
1.1       mycroft  1358:        register struct vnode *vp, **vpp = ap->a_vpp;
                   1359:        register struct inode *ip;
                   1360:        int len, error;
                   1361:
1.15      christos 1362:        error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
                   1363:                              vpp, ap->a_cnp);
                   1364:        if (error)
1.1       mycroft  1365:                return (error);
                   1366:        vp = *vpp;
                   1367:        len = strlen(ap->a_target);
                   1368:        if (len < vp->v_mount->mnt_maxsymlinklen) {
                   1369:                ip = VTOI(vp);
1.26    ! bouyer   1370:                bcopy(ap->a_target, (char *)ip->i_ffs_shortlink, len);
        !          1371:                ip->i_ffs_size = len;
1.1       mycroft  1372:                ip->i_flag |= IN_CHANGE | IN_UPDATE;
                   1373:        } else
                   1374:                error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
                   1375:                    UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
                   1376:                    (struct proc *)0);
                   1377:        vput(vp);
                   1378:        return (error);
                   1379: }
                   1380:
                   1381: /*
                   1382:  * Vnode op for reading directories.
                   1383:  *
                   1384:  * The routine below assumes that the on-disk format of a directory
                   1385:  * is the same as that defined by <sys/dirent.h>. If the on-disk
                   1386:  * format changes, then it will be necessary to do a conversion
                   1387:  * from the on-disk format that read returns to the format defined
                   1388:  * by <sys/dirent.h>.
                   1389:  */
                   1390: int
1.15      christos 1391: ufs_readdir(v)
                   1392:        void *v;
                   1393: {
1.1       mycroft  1394:        struct vop_readdir_args /* {
                   1395:                struct vnode *a_vp;
                   1396:                struct uio *a_uio;
                   1397:                struct ucred *a_cred;
                   1398:                int *a_eofflag;
                   1399:                u_long *a_cookies;
                   1400:                int ncookies;
1.15      christos 1401:        } */ *ap = v;
1.1       mycroft  1402:        register struct uio *uio = ap->a_uio;
                   1403:        int error;
                   1404:        size_t count, lost;
                   1405:        off_t off = uio->uio_offset;
                   1406:
                   1407:        count = uio->uio_resid;
                   1408:        /* Make sure we don't return partial entries. */
                   1409:        count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
                   1410:        if (count <= 0)
                   1411:                return (EINVAL);
                   1412:        lost = uio->uio_resid - count;
                   1413:        uio->uio_resid = count;
                   1414:        uio->uio_iov->iov_len = count;
                   1415: #      if (BYTE_ORDER == LITTLE_ENDIAN)
                   1416:                if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) {
                   1417:                        error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
                   1418:                } else {
                   1419:                        struct dirent *dp, *edp;
                   1420:                        struct uio auio;
                   1421:                        struct iovec aiov;
                   1422:                        caddr_t dirbuf;
                   1423:                        int readcnt;
                   1424:                        u_char tmp;
                   1425:
                   1426:                        auio = *uio;
                   1427:                        auio.uio_iov = &aiov;
                   1428:                        auio.uio_iovcnt = 1;
                   1429:                        auio.uio_segflg = UIO_SYSSPACE;
                   1430:                        aiov.iov_len = count;
                   1431:                        MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
                   1432:                        aiov.iov_base = dirbuf;
                   1433:                        error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
                   1434:                        if (error == 0) {
                   1435:                                readcnt = count - auio.uio_resid;
                   1436:                                edp = (struct dirent *)&dirbuf[readcnt];
                   1437:                                for (dp = (struct dirent *)dirbuf; dp < edp; ) {
                   1438:                                        tmp = dp->d_namlen;
                   1439:                                        dp->d_namlen = dp->d_type;
                   1440:                                        dp->d_type = tmp;
                   1441:                                        if (dp->d_reclen > 0) {
                   1442:                                                dp = (struct dirent *)
                   1443:                                                    ((char *)dp + dp->d_reclen);
                   1444:                                        } else {
                   1445:                                                error = EIO;
                   1446:                                                break;
                   1447:                                        }
                   1448:                                }
                   1449:                                if (dp >= edp)
                   1450:                                        error = uiomove(dirbuf, readcnt, uio);
                   1451:                        }
                   1452:                        FREE(dirbuf, M_TEMP);
                   1453:                }
                   1454: #      else
                   1455:                error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
                   1456: #      endif
                   1457:        if (!error && ap->a_ncookies) {
                   1458:                register struct dirent *dp;
                   1459:                register u_long *cookies = ap->a_cookies;
                   1460:                register int ncookies = ap->a_ncookies;
                   1461:
                   1462:                /*
1.11      mycroft  1463:                 * Only the NFS server and emulations use cookies, and they
                   1464:                 * load the directory block into system space, so we can
                   1465:                 * just look at it directly.
1.1       mycroft  1466:                 */
                   1467:                if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
                   1468:                        panic("ufs_readdir: lost in space");
                   1469:                dp = (struct dirent *)
                   1470:                     (uio->uio_iov->iov_base - (uio->uio_offset - off));
                   1471:                while (ncookies-- && off < uio->uio_offset) {
                   1472:                        if (dp->d_reclen == 0)
                   1473:                                break;
                   1474:                        off += dp->d_reclen;
                   1475:                        *(cookies++) = off;
                   1476:                        dp = (struct dirent *)((caddr_t)dp + dp->d_reclen);
                   1477:                }
                   1478:                lost += uio->uio_offset - off;
                   1479:                uio->uio_offset = off;
                   1480:        }
                   1481:        uio->uio_resid += lost;
1.26    ! bouyer   1482:        *ap->a_eofflag = VTOI(ap->a_vp)->i_ffs_size <= uio->uio_offset;
1.1       mycroft  1483:        return (error);
                   1484: }
                   1485:
                   1486: /*
                   1487:  * Return target name of a symbolic link
                   1488:  */
                   1489: int
1.15      christos 1490: ufs_readlink(v)
                   1491:        void *v;
                   1492: {
1.1       mycroft  1493:        struct vop_readlink_args /* {
                   1494:                struct vnode *a_vp;
                   1495:                struct uio *a_uio;
                   1496:                struct ucred *a_cred;
1.15      christos 1497:        } */ *ap = v;
1.1       mycroft  1498:        register struct vnode *vp = ap->a_vp;
                   1499:        register struct inode *ip = VTOI(vp);
                   1500:        int isize;
                   1501:
1.26    ! bouyer   1502:        isize = ip->i_ffs_size;
1.1       mycroft  1503:        if (isize < vp->v_mount->mnt_maxsymlinklen ||
1.26    ! bouyer   1504:            (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_ffs_blocks == 0)) {
        !          1505:                uiomove((char *)ip->i_ffs_shortlink, isize, ap->a_uio);
1.1       mycroft  1506:                return (0);
                   1507:        }
                   1508:        return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
                   1509: }
                   1510:
                   1511: /*
                   1512:  * Lock an inode. If its already locked, set the WANT bit and sleep.
                   1513:  */
                   1514: int
1.15      christos 1515: ufs_lock(v)
                   1516:        void *v;
                   1517: {
1.1       mycroft  1518:        struct vop_lock_args /* {
                   1519:                struct vnode *a_vp;
1.15      christos 1520:        } */ *ap = v;
1.1       mycroft  1521:        register struct vnode *vp = ap->a_vp;
                   1522:        register struct inode *ip;
1.15      christos 1523: #ifdef DIAGNOSTIC
1.1       mycroft  1524:        struct proc *p = curproc;       /* XXX */
1.15      christos 1525: #endif
1.1       mycroft  1526:
                   1527: start:
                   1528:        while (vp->v_flag & VXLOCK) {
                   1529:                vp->v_flag |= VXWANT;
                   1530:                sleep((caddr_t)vp, PINOD);
                   1531:        }
                   1532:        if (vp->v_tag == VT_NON)
                   1533:                return (ENOENT);
                   1534:        ip = VTOI(vp);
                   1535:        if (ip->i_flag & IN_LOCKED) {
                   1536:                ip->i_flag |= IN_WANTED;
                   1537: #ifdef DIAGNOSTIC
                   1538:                if (p) {
                   1539:                        if (p->p_pid == ip->i_lockholder)
                   1540:                                panic("locking against myself");
                   1541:                        ip->i_lockwaiter = p->p_pid;
                   1542:                } else
                   1543:                        ip->i_lockwaiter = -1;
                   1544: #endif
                   1545:                (void) sleep((caddr_t)ip, PINOD);
                   1546:                goto start;
                   1547:        }
                   1548: #ifdef DIAGNOSTIC
                   1549:        ip->i_lockwaiter = 0;
                   1550:        if (ip->i_lockholder != 0)
                   1551:                panic("lockholder (%d) != 0", ip->i_lockholder);
                   1552:        if (p && p->p_pid == 0)
1.21      christos 1553:                printf("locking by process 0\n");
1.1       mycroft  1554:        if (p)
                   1555:                ip->i_lockholder = p->p_pid;
                   1556:        else
                   1557:                ip->i_lockholder = -1;
                   1558: #endif
                   1559:        ip->i_flag |= IN_LOCKED;
                   1560:        return (0);
                   1561: }
                   1562:
                   1563: /*
                   1564:  * Unlock an inode.  If WANT bit is on, wakeup.
                   1565:  */
                   1566: int lockcount = 90;
                   1567: int
1.15      christos 1568: ufs_unlock(v)
                   1569:        void *v;
                   1570: {
1.1       mycroft  1571:        struct vop_unlock_args /* {
                   1572:                struct vnode *a_vp;
1.15      christos 1573:        } */ *ap = v;
1.1       mycroft  1574:        register struct inode *ip = VTOI(ap->a_vp);
1.15      christos 1575: #ifdef DIAGNOSTIC
1.1       mycroft  1576:        struct proc *p = curproc;       /* XXX */
1.15      christos 1577: #endif
1.1       mycroft  1578:
                   1579: #ifdef DIAGNOSTIC
                   1580:        if ((ip->i_flag & IN_LOCKED) == 0) {
                   1581:                vprint("ufs_unlock: unlocked inode", ap->a_vp);
                   1582:                panic("ufs_unlock NOT LOCKED");
                   1583:        }
                   1584:        if (p && p->p_pid != ip->i_lockholder && p->p_pid > -1 &&
                   1585:            ip->i_lockholder > -1 && lockcount++ < 100)
                   1586:                panic("unlocker (%d) != lock holder (%d)",
                   1587:                    p->p_pid, ip->i_lockholder);
                   1588:        ip->i_lockholder = 0;
                   1589: #endif
                   1590:        ip->i_flag &= ~IN_LOCKED;
                   1591:        if (ip->i_flag & IN_WANTED) {
                   1592:                ip->i_flag &= ~IN_WANTED;
                   1593:                wakeup((caddr_t)ip);
                   1594:        }
                   1595:        return (0);
                   1596: }
                   1597:
                   1598: /*
                   1599:  * Check for a locked inode.
                   1600:  */
                   1601: int
1.15      christos 1602: ufs_islocked(v)
                   1603:        void *v;
                   1604: {
1.1       mycroft  1605:        struct vop_islocked_args /* {
                   1606:                struct vnode *a_vp;
1.15      christos 1607:        } */ *ap = v;
1.1       mycroft  1608:
                   1609:        if (VTOI(ap->a_vp)->i_flag & IN_LOCKED)
                   1610:                return (1);
                   1611:        return (0);
                   1612: }
                   1613:
                   1614: /*
                   1615:  * Calculate the logical to physical mapping if not done already,
                   1616:  * then call the device strategy routine.
                   1617:  */
                   1618: int
1.15      christos 1619: ufs_strategy(v)
                   1620:        void *v;
                   1621: {
1.1       mycroft  1622:        struct vop_strategy_args /* {
                   1623:                struct buf *a_bp;
1.15      christos 1624:        } */ *ap = v;
1.1       mycroft  1625:        register struct buf *bp = ap->a_bp;
                   1626:        register struct vnode *vp = bp->b_vp;
                   1627:        register struct inode *ip;
                   1628:        int error;
                   1629:
                   1630:        ip = VTOI(vp);
                   1631:        if (vp->v_type == VBLK || vp->v_type == VCHR)
                   1632:                panic("ufs_strategy: spec");
                   1633:        if (bp->b_blkno == bp->b_lblkno) {
1.15      christos 1634:                error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno,
                   1635:                                 NULL);
                   1636:                if (error) {
1.1       mycroft  1637:                        bp->b_error = error;
                   1638:                        bp->b_flags |= B_ERROR;
                   1639:                        biodone(bp);
                   1640:                        return (error);
                   1641:                }
                   1642:                if ((long)bp->b_blkno == -1)
                   1643:                        clrbuf(bp);
                   1644:        }
                   1645:        if ((long)bp->b_blkno == -1) {
                   1646:                biodone(bp);
                   1647:                return (0);
                   1648:        }
                   1649:        vp = ip->i_devvp;
                   1650:        bp->b_dev = vp->v_rdev;
                   1651:        VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
                   1652:        return (0);
                   1653: }
                   1654:
                   1655: /*
                   1656:  * Print out the contents of an inode.
                   1657:  */
                   1658: int
1.15      christos 1659: ufs_print(v)
                   1660:        void *v;
                   1661: {
1.1       mycroft  1662:        struct vop_print_args /* {
                   1663:                struct vnode *a_vp;
1.15      christos 1664:        } */ *ap = v;
1.1       mycroft  1665:        register struct vnode *vp = ap->a_vp;
                   1666:        register struct inode *ip = VTOI(vp);
                   1667:
1.21      christos 1668:        printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number,
1.20      christos 1669:            major(ip->i_dev), minor(ip->i_dev));
1.1       mycroft  1670: #ifdef FIFO
                   1671:        if (vp->v_type == VFIFO)
                   1672:                fifo_printinfo(vp);
                   1673: #endif /* FIFO */
1.21      christos 1674:        printf("%s\n", (ip->i_flag & IN_LOCKED) ? " (LOCKED)" : "");
1.1       mycroft  1675:        if (ip->i_lockholder == 0)
                   1676:                return (0);
1.21      christos 1677:        printf("\towner pid %d", ip->i_lockholder);
1.1       mycroft  1678:        if (ip->i_lockwaiter)
1.21      christos 1679:                printf(" waiting pid %d", ip->i_lockwaiter);
                   1680:        printf("\n");
1.1       mycroft  1681:        return (0);
                   1682: }
                   1683:
                   1684: /*
                   1685:  * Read wrapper for special devices.
                   1686:  */
                   1687: int
1.15      christos 1688: ufsspec_read(v)
                   1689:        void *v;
                   1690: {
1.1       mycroft  1691:        struct vop_read_args /* {
                   1692:                struct vnode *a_vp;
                   1693:                struct uio *a_uio;
                   1694:                int  a_ioflag;
                   1695:                struct ucred *a_cred;
1.15      christos 1696:        } */ *ap = v;
1.1       mycroft  1697:
                   1698:        /*
                   1699:         * Set access flag.
                   1700:         */
                   1701:        VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
                   1702:        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
                   1703: }
                   1704:
                   1705: /*
                   1706:  * Write wrapper for special devices.
                   1707:  */
                   1708: int
1.15      christos 1709: ufsspec_write(v)
                   1710:        void *v;
                   1711: {
1.1       mycroft  1712:        struct vop_write_args /* {
                   1713:                struct vnode *a_vp;
                   1714:                struct uio *a_uio;
                   1715:                int  a_ioflag;
                   1716:                struct ucred *a_cred;
1.15      christos 1717:        } */ *ap = v;
1.1       mycroft  1718:
                   1719:        /*
                   1720:         * Set update and change flags.
                   1721:         */
                   1722:        VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
                   1723:        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
                   1724: }
                   1725:
                   1726: /*
                   1727:  * Close wrapper for special devices.
                   1728:  *
                   1729:  * Update the times on the inode then do device close.
                   1730:  */
                   1731: int
1.15      christos 1732: ufsspec_close(v)
                   1733:        void *v;
                   1734: {
1.1       mycroft  1735:        struct vop_close_args /* {
                   1736:                struct vnode *a_vp;
                   1737:                int  a_fflag;
                   1738:                struct ucred *a_cred;
                   1739:                struct proc *a_p;
1.15      christos 1740:        } */ *ap = v;
1.1       mycroft  1741:        register struct inode *ip = VTOI(ap->a_vp);
1.19      mycroft  1742:        struct timespec ts;
1.1       mycroft  1743:
1.19      mycroft  1744:        if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED)) {
                   1745:                TIMEVAL_TO_TIMESPEC(&time, &ts);
                   1746:                ITIMES(ip, &ts, &ts, &ts);
                   1747:        }
1.1       mycroft  1748:        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
                   1749: }
                   1750:
                   1751: #ifdef FIFO
                   1752: /*
                   1753:  * Read wrapper for fifo's
                   1754:  */
                   1755: int
1.15      christos 1756: ufsfifo_read(v)
                   1757:        void *v;
                   1758: {
1.1       mycroft  1759:        struct vop_read_args /* {
                   1760:                struct vnode *a_vp;
                   1761:                struct uio *a_uio;
                   1762:                int  a_ioflag;
                   1763:                struct ucred *a_cred;
1.15      christos 1764:        } */ *ap = v;
                   1765:        extern int (**fifo_vnodeop_p) __P((void *));
1.1       mycroft  1766:
                   1767:        /*
                   1768:         * Set access flag.
                   1769:         */
                   1770:        VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
                   1771:        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
                   1772: }
                   1773:
                   1774: /*
                   1775:  * Write wrapper for fifo's.
                   1776:  */
                   1777: int
1.15      christos 1778: ufsfifo_write(v)
                   1779:        void *v;
                   1780: {
1.1       mycroft  1781:        struct vop_write_args /* {
                   1782:                struct vnode *a_vp;
                   1783:                struct uio *a_uio;
                   1784:                int  a_ioflag;
                   1785:                struct ucred *a_cred;
1.15      christos 1786:        } */ *ap = v;
                   1787:        extern int (**fifo_vnodeop_p) __P((void *));
1.1       mycroft  1788:
                   1789:        /*
                   1790:         * Set update and change flags.
                   1791:         */
                   1792:        VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
                   1793:        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
                   1794: }
                   1795:
                   1796: /*
                   1797:  * Close wrapper for fifo's.
                   1798:  *
                   1799:  * Update the times on the inode then do device close.
                   1800:  */
1.15      christos 1801: int
                   1802: ufsfifo_close(v)
                   1803:        void *v;
                   1804: {
1.1       mycroft  1805:        struct vop_close_args /* {
                   1806:                struct vnode *a_vp;
                   1807:                int  a_fflag;
                   1808:                struct ucred *a_cred;
                   1809:                struct proc *a_p;
1.15      christos 1810:        } */ *ap = v;
                   1811:        extern int (**fifo_vnodeop_p) __P((void *));
1.1       mycroft  1812:        register struct inode *ip = VTOI(ap->a_vp);
1.19      mycroft  1813:        struct timespec ts;
1.1       mycroft  1814:
1.19      mycroft  1815:        if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED)) {
                   1816:                TIMEVAL_TO_TIMESPEC(&time, &ts);
                   1817:                ITIMES(ip, &ts, &ts, &ts);
                   1818:        }
1.1       mycroft  1819:        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
                   1820: }
                   1821: #endif /* FIFO */
                   1822:
                   1823: /*
                   1824:  * Return POSIX pathconf information applicable to ufs filesystems.
                   1825:  */
1.15      christos 1826: int
                   1827: ufs_pathconf(v)
                   1828:        void *v;
                   1829: {
1.1       mycroft  1830:        struct vop_pathconf_args /* {
                   1831:                struct vnode *a_vp;
                   1832:                int a_name;
1.4       cgd      1833:                register_t *a_retval;
1.15      christos 1834:        } */ *ap = v;
1.1       mycroft  1835:
                   1836:        switch (ap->a_name) {
                   1837:        case _PC_LINK_MAX:
                   1838:                *ap->a_retval = LINK_MAX;
                   1839:                return (0);
                   1840:        case _PC_NAME_MAX:
                   1841:                *ap->a_retval = NAME_MAX;
                   1842:                return (0);
                   1843:        case _PC_PATH_MAX:
                   1844:                *ap->a_retval = PATH_MAX;
                   1845:                return (0);
                   1846:        case _PC_PIPE_BUF:
                   1847:                *ap->a_retval = PIPE_BUF;
                   1848:                return (0);
                   1849:        case _PC_CHOWN_RESTRICTED:
                   1850:                *ap->a_retval = 1;
                   1851:                return (0);
                   1852:        case _PC_NO_TRUNC:
                   1853:                *ap->a_retval = 1;
                   1854:                return (0);
                   1855:        default:
                   1856:                return (EINVAL);
                   1857:        }
                   1858:        /* NOTREACHED */
                   1859: }
                   1860:
                   1861: /*
                   1862:  * Advisory record locking support
                   1863:  */
                   1864: int
1.15      christos 1865: ufs_advlock(v)
                   1866:        void *v;
                   1867: {
1.1       mycroft  1868:        struct vop_advlock_args /* {
                   1869:                struct vnode *a_vp;
                   1870:                caddr_t  a_id;
                   1871:                int  a_op;
                   1872:                struct flock *a_fl;
                   1873:                int  a_flags;
1.15      christos 1874:        } */ *ap = v;
1.1       mycroft  1875:        register struct inode *ip = VTOI(ap->a_vp);
                   1876:
1.26    ! bouyer   1877:        return (lf_advlock(&ip->i_lockf, ip->i_ffs_size, ap->a_id, ap->a_op,
1.1       mycroft  1878:            ap->a_fl, ap->a_flags));
                   1879: }
                   1880:
                   1881: /*
                   1882:  * Initialize the vnode associated with a new inode, handle aliased
                   1883:  * vnodes.
                   1884:  */
                   1885: int
                   1886: ufs_vinit(mntp, specops, fifoops, vpp)
                   1887:        struct mount *mntp;
1.15      christos 1888:        int (**specops) __P((void *));
                   1889:        int (**fifoops) __P((void *));
1.1       mycroft  1890:        struct vnode **vpp;
                   1891: {
                   1892:        struct inode *ip;
                   1893:        struct vnode *vp, *nvp;
                   1894:
                   1895:        vp = *vpp;
                   1896:        ip = VTOI(vp);
1.26    ! bouyer   1897:        switch(vp->v_type = IFTOVT(ip->i_ffs_mode)) {
1.1       mycroft  1898:        case VCHR:
                   1899:        case VBLK:
                   1900:                vp->v_op = specops;
1.26    ! bouyer   1901:                if ((nvp = checkalias(vp, ip->i_ffs_rdev, mntp)) != NULL) {
1.1       mycroft  1902:                        /*
                   1903:                         * Discard unneeded vnode, but save its inode.
                   1904:                         */
                   1905:                        ufs_ihashrem(ip);
                   1906:                        VOP_UNLOCK(vp);
                   1907:                        nvp->v_data = vp->v_data;
                   1908:                        vp->v_data = NULL;
                   1909:                        vp->v_op = spec_vnodeop_p;
                   1910:                        vrele(vp);
                   1911:                        vgone(vp);
                   1912:                        /*
                   1913:                         * Reinitialize aliased inode.
                   1914:                         */
                   1915:                        vp = nvp;
                   1916:                        ip->i_vnode = vp;
                   1917:                        ufs_ihashins(ip);
                   1918:                }
                   1919:                break;
                   1920:        case VFIFO:
                   1921: #ifdef FIFO
                   1922:                vp->v_op = fifoops;
                   1923:                break;
                   1924: #else
                   1925:                return (EOPNOTSUPP);
                   1926: #endif
1.15      christos 1927:        case VNON:
                   1928:        case VBAD:
                   1929:        case VSOCK:
                   1930:        case VLNK:
                   1931:        case VDIR:
                   1932:        case VREG:
                   1933:                break;
1.1       mycroft  1934:        }
                   1935:        if (ip->i_number == ROOTINO)
                   1936:                 vp->v_flag |= VROOT;
                   1937:        /*
                   1938:         * Initialize modrev times
                   1939:         */
                   1940:        SETHIGH(ip->i_modrev, mono_time.tv_sec);
                   1941:        SETLOW(ip->i_modrev, mono_time.tv_usec * 4294);
                   1942:        *vpp = vp;
                   1943:        return (0);
                   1944: }
                   1945:
                   1946: /*
                   1947:  * Allocate a new inode.
                   1948:  */
                   1949: int
                   1950: ufs_makeinode(mode, dvp, vpp, cnp)
                   1951:        int mode;
                   1952:        struct vnode *dvp;
                   1953:        struct vnode **vpp;
                   1954:        struct componentname *cnp;
                   1955: {
                   1956:        register struct inode *ip, *pdir;
1.18      mycroft  1957:        struct timespec ts;
1.1       mycroft  1958:        struct vnode *tvp;
                   1959:        int error;
                   1960:
                   1961:        pdir = VTOI(dvp);
                   1962: #ifdef DIAGNOSTIC
                   1963:        if ((cnp->cn_flags & HASBUF) == 0)
                   1964:                panic("ufs_makeinode: no name");
                   1965: #endif
                   1966:        *vpp = NULL;
                   1967:        if ((mode & IFMT) == 0)
                   1968:                mode |= IFREG;
                   1969:
1.15      christos 1970:        if ((error = VOP_VALLOC(dvp, mode, cnp->cn_cred, &tvp)) != 0) {
1.1       mycroft  1971:                free(cnp->cn_pnbuf, M_NAMEI);
                   1972:                vput(dvp);
                   1973:                return (error);
                   1974:        }
                   1975:        ip = VTOI(tvp);
1.26    ! bouyer   1976:        ip->i_ffs_gid = pdir->i_ffs_gid;
        !          1977:        ip->i_ffs_uid = cnp->cn_cred->cr_uid;
1.1       mycroft  1978: #ifdef QUOTA
                   1979:        if ((error = getinoquota(ip)) ||
                   1980:            (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
                   1981:                free(cnp->cn_pnbuf, M_NAMEI);
                   1982:                VOP_VFREE(tvp, ip->i_number, mode);
                   1983:                vput(tvp);
                   1984:                vput(dvp);
                   1985:                return (error);
                   1986:        }
                   1987: #endif
                   1988:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1.26    ! bouyer   1989:        ip->i_ffs_mode = mode;
1.1       mycroft  1990:        tvp->v_type = IFTOVT(mode);     /* Rest init'd in getnewvnode(). */
1.26    ! bouyer   1991:        ip->i_ffs_nlink = 1;
        !          1992:        if ((ip->i_ffs_mode & ISGID) &&
        !          1993:                !groupmember(ip->i_ffs_gid, cnp->cn_cred) &&
1.1       mycroft  1994:            suser(cnp->cn_cred, NULL))
1.26    ! bouyer   1995:                ip->i_ffs_mode &= ~ISGID;
1.6       mycroft  1996:
                   1997:        if (cnp->cn_flags & ISWHITEOUT)
1.26    ! bouyer   1998:                ip->i_ffs_flags |= UF_OPAQUE;
1.1       mycroft  1999:
                   2000:        /*
                   2001:         * Make sure inode goes to disk before directory entry.
                   2002:         */
1.18      mycroft  2003:        TIMEVAL_TO_TIMESPEC(&time, &ts);
                   2004:        if ((error = VOP_UPDATE(tvp, &ts, &ts, 1)) != 0)
1.1       mycroft  2005:                goto bad;
1.15      christos 2006:        if ((error = ufs_direnter(ip, dvp, cnp)) != 0)
1.1       mycroft  2007:                goto bad;
                   2008:        if ((cnp->cn_flags & SAVESTART) == 0)
                   2009:                FREE(cnp->cn_pnbuf, M_NAMEI);
                   2010:        vput(dvp);
                   2011:        *vpp = tvp;
                   2012:        return (0);
                   2013:
                   2014: bad:
                   2015:        /*
                   2016:         * Write error occurred trying to update the inode
                   2017:         * or the directory so must deallocate the inode.
                   2018:         */
                   2019:        free(cnp->cn_pnbuf, M_NAMEI);
                   2020:        vput(dvp);
1.26    ! bouyer   2021:        ip->i_ffs_nlink = 0;
1.1       mycroft  2022:        ip->i_flag |= IN_CHANGE;
                   2023:        vput(tvp);
                   2024:        return (error);
                   2025: }

CVSweb <webmaster@jp.NetBSD.org>