[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.66

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

CVSweb <webmaster@jp.NetBSD.org>