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

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

CVSweb <webmaster@jp.NetBSD.org>