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

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

CVSweb <webmaster@jp.NetBSD.org>