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

Annotation of src/sys/ufs/ext2fs/ext2fs_vnops.c, Revision 1.110

1.110   ! hannken     1: /*     $NetBSD: ext2fs_vnops.c,v 1.109 2014/01/21 07:53:38 hannken Exp $       */
1.1       bouyer      2:
                      3: /*
                      4:  * Copyright (c) 1982, 1986, 1989, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  * (c) UNIX System Laboratories, Inc.
                      7:  * All or some portions of this file are derived from material licensed
                      8:  * to the University of California by American Telephone and Telegraph
                      9:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     10:  * the permission of UNIX System Laboratories, Inc.
                     11:  *
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 1. Redistributions of source code must retain the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer.
                     17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
                     19:  *    documentation and/or other materials provided with the distribution.
1.49      agc        20:  * 3. Neither the name of the University nor the names of its contributors
                     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:  *
                     36:  *     @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
                     37:  * Modified for ext2fs by Manuel Bouyer.
                     38:  */
                     39:
                     40: /*
                     41:  * Copyright (c) 1997 Manuel Bouyer.
                     42:  *
                     43:  * Redistribution and use in source and binary forms, with or without
                     44:  * modification, are permitted provided that the following conditions
                     45:  * are met:
                     46:  * 1. Redistributions of source code must retain the above copyright
                     47:  *    notice, this list of conditions and the following disclaimer.
                     48:  * 2. Redistributions in binary form must reproduce the above copyright
                     49:  *    notice, this list of conditions and the following disclaimer in the
                     50:  *    documentation and/or other materials provided with the distribution.
1.1       bouyer     51:  *
1.52      bouyer     52:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     53:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     54:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     55:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     56:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     57:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     58:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     59:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     60:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     61:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1       bouyer     62:  *
                     63:  *     @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
                     64:  * Modified for ext2fs by Manuel Bouyer.
                     65:  */
1.40      lukem      66:
                     67: #include <sys/cdefs.h>
1.110   ! hannken    68: __KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.109 2014/01/21 07:53:38 hannken Exp $");
1.7       mrg        69:
1.1       bouyer     70: #include <sys/param.h>
                     71: #include <sys/systm.h>
                     72: #include <sys/resourcevar.h>
                     73: #include <sys/kernel.h>
                     74: #include <sys/file.h>
                     75: #include <sys/stat.h>
                     76: #include <sys/buf.h>
                     77: #include <sys/proc.h>
                     78: #include <sys/mount.h>
                     79: #include <sys/namei.h>
                     80: #include <sys/vnode.h>
                     81: #include <sys/lockf.h>
                     82: #include <sys/malloc.h>
1.14      thorpej    83: #include <sys/pool.h>
1.1       bouyer     84: #include <sys/signalvar.h>
1.65      elad       85: #include <sys/kauth.h>
1.1       bouyer     86:
                     87: #include <miscfs/fifofs/fifo.h>
                     88: #include <miscfs/genfs/genfs.h>
                     89: #include <miscfs/specfs/specdev.h>
                     90:
                     91: #include <ufs/ufs/inode.h>
                     92: #include <ufs/ufs/ufs_extern.h>
                     93: #include <ufs/ufs/ufsmount.h>
                     94:
                     95: #include <ufs/ext2fs/ext2fs.h>
                     96: #include <ufs/ext2fs/ext2fs_extern.h>
                     97: #include <ufs/ext2fs/ext2fs_dir.h>
                     98:
1.32      tsutsui    99: extern int prtactive;
1.1       bouyer    100:
1.67      ad        101: static int ext2fs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
1.65      elad      102: static int ext2fs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
1.67      ad        103:                                struct lwp *);
1.1       bouyer    104:
                    105: union _qcvt {
                    106:        int64_t qcvt;
                    107:        int32_t val[2];
                    108: };
1.61      xtraeme   109:
1.1       bouyer    110: #define SETHIGH(q, h) { \
                    111:        union _qcvt tmp; \
                    112:        tmp.qcvt = (q); \
                    113:        tmp.val[_QUAD_HIGHWORD] = (h); \
                    114:        (q) = tmp.qcvt; \
                    115: }
                    116: #define SETLOW(q, l) { \
                    117:        union _qcvt tmp; \
                    118:        tmp.qcvt = (q); \
                    119:        tmp.val[_QUAD_LOWWORD] = (l); \
                    120:        (q) = tmp.qcvt; \
                    121: }
                    122:
                    123: /*
                    124:  * Create a regular file
                    125:  */
                    126: int
1.61      xtraeme   127: ext2fs_create(void *v)
1.1       bouyer    128: {
1.110   ! hannken   129:        struct vop_create_v3_args /* {
1.1       bouyer    130:                struct vnode *a_dvp;
                    131:                struct vnode **a_vpp;
                    132:                struct componentname *a_cnp;
                    133:                struct vattr *a_vap;
                    134:        } */ *ap = v;
1.42      jdolecek  135:        int     error;
                    136:
                    137:        error =
                    138:            ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
                    139:                             ap->a_dvp, ap->a_vpp, ap->a_cnp);
                    140:
                    141:        if (error)
                    142:                return (error);
                    143:        VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.110   ! hannken   144:        VOP_UNLOCK(*ap->a_vpp);
1.42      jdolecek  145:        return (0);
1.1       bouyer    146: }
                    147:
                    148: /*
                    149:  * Mknod vnode call
                    150:  */
                    151: /* ARGSUSED */
                    152: int
1.61      xtraeme   153: ext2fs_mknod(void *v)
1.1       bouyer    154: {
1.110   ! hannken   155:        struct vop_mknod_v3_args /* {
1.1       bouyer    156:                struct vnode *a_dvp;
                    157:                struct vnode **a_vpp;
                    158:                struct componentname *a_cnp;
                    159:                struct vattr *a_vap;
                    160:        } */ *ap = v;
1.25      augustss  161:        struct vattr *vap = ap->a_vap;
                    162:        struct vnode **vpp = ap->a_vpp;
                    163:        struct inode *ip;
1.1       bouyer    164:        int error;
1.59      perry     165:        struct mount    *mp;
1.34      assar     166:        ino_t           ino;
1.1       bouyer    167:
1.8       fvdl      168:        if ((error = ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
                    169:                    ap->a_dvp, vpp, ap->a_cnp)) != 0)
1.1       bouyer    170:                return (error);
1.42      jdolecek  171:        VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.1       bouyer    172:        ip = VTOI(*vpp);
1.34      assar     173:        mp  = (*vpp)->v_mount;
                    174:        ino = ip->i_number;
1.1       bouyer    175:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
                    176:        if (vap->va_rdev != VNOVAL) {
                    177:                /*
                    178:                 * Want to be able to use this to make badblock
                    179:                 * inodes, so don't truncate the dev number.
                    180:                 */
1.44      fvdl      181:                ip->i_din.e2fs_din->e2di_rdev = h2fs32(vap->va_rdev);
1.1       bouyer    182:        }
                    183:        /*
                    184:         * Remove inode so that it will be reloaded by VFS_VGET and
                    185:         * checked to see if it is an alias of an existing entry in
                    186:         * the inode cache.
                    187:         */
1.109     hannken   188:        (*vpp)->v_type = VNON;
1.93      hannken   189:        VOP_UNLOCK(*vpp);
1.1       bouyer    190:        vgone(*vpp);
1.47      thorpej   191:        error = VFS_VGET(mp, ino, vpp);
1.34      assar     192:        if (error != 0) {
                    193:                *vpp = NULL;
                    194:                return (error);
                    195:        }
1.110   ! hannken   196:        VOP_UNLOCK(*vpp);
1.1       bouyer    197:        return (0);
                    198: }
                    199:
                    200: /*
                    201:  * Open called.
                    202:  *
                    203:  * Just check the APPEND flag.
                    204:  */
                    205: /* ARGSUSED */
                    206: int
1.61      xtraeme   207: ext2fs_open(void *v)
1.1       bouyer    208: {
                    209:        struct vop_open_args /* {
                    210:                struct vnode *a_vp;
                    211:                int  a_mode;
1.65      elad      212:                kauth_cred_t a_cred;
1.1       bouyer    213:        } */ *ap = v;
                    214:
                    215:        /*
                    216:         * Files marked append-only must be opened for appending.
                    217:         */
                    218:        if ((VTOI(ap->a_vp)->i_e2fs_flags & EXT2_APPEND) &&
                    219:                (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
                    220:                return (EPERM);
                    221:        return (0);
                    222: }
                    223:
1.88      elad      224: static int
                    225: ext2fs_check_possible(struct vnode *vp, struct inode *ip, mode_t mode)
1.1       bouyer    226: {
                    227:
1.8       fvdl      228:        /*
                    229:         * Disallow write attempts on read-only file systems;
                    230:         * unless the file is a socket, fifo, or a block or
                    231:         * character device resident on the file system.
                    232:         */
                    233:        if (mode & VWRITE) {
                    234:                switch (vp->v_type) {
                    235:                case VDIR:
                    236:                case VLNK:
                    237:                case VREG:
                    238:                        if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    239:                                return (EROFS);
                    240:                        break;
                    241:                default:
                    242:                        break;
                    243:                }
1.1       bouyer    244:        }
                    245:
                    246:        /* If immutable bit set, nobody gets to write it. */
                    247:        if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE))
                    248:                return (EPERM);
                    249:
1.88      elad      250:        return 0;
                    251: }
                    252:
                    253: static int
                    254: ext2fs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode,
                    255:     kauth_cred_t cred)
                    256: {
                    257:
1.107     plunky    258:        return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
1.102     elad      259:            ip->i_e2fs_mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
                    260:            ip->i_e2fs_mode & ALLPERMS, ip->i_uid, ip->i_gid, mode, cred));
1.88      elad      261: }
                    262:
                    263: int
                    264: ext2fs_access(void *v)
                    265: {
                    266:        struct vop_access_args /* {
                    267:                struct vnode *a_vp;
                    268:                int  a_mode;
                    269:                kauth_cred_t a_cred;
                    270:        } */ *ap = v;
                    271:        struct vnode *vp = ap->a_vp;
                    272:        struct inode *ip = VTOI(vp);
                    273:        mode_t mode = ap->a_mode;
                    274:        int error;
                    275:
                    276:        error = ext2fs_check_possible(vp, ip, mode);
                    277:        if (error)
                    278:                return error;
                    279:
                    280:        error = ext2fs_check_permitted(vp, ip, mode, ap->a_cred);
                    281:
                    282:        return error;
1.1       bouyer    283: }
                    284:
                    285: /* ARGSUSED */
                    286: int
1.61      xtraeme   287: ext2fs_getattr(void *v)
1.1       bouyer    288: {
                    289:        struct vop_getattr_args /* {
                    290:                struct vnode *a_vp;
                    291:                struct vattr *a_vap;
1.65      elad      292:                kauth_cred_t a_cred;
1.1       bouyer    293:        } */ *ap = v;
1.25      augustss  294:        struct vnode *vp = ap->a_vp;
                    295:        struct inode *ip = VTOI(vp);
                    296:        struct vattr *vap = ap->a_vap;
1.1       bouyer    297:
1.62      christos  298:        EXT2FS_ITIMES(ip, NULL, NULL, NULL);
1.1       bouyer    299:        /*
                    300:         * Copy from inode table
                    301:         */
                    302:        vap->va_fsid = ip->i_dev;
                    303:        vap->va_fileid = ip->i_number;
                    304:        vap->va_mode = ip->i_e2fs_mode & ALLPERMS;
                    305:        vap->va_nlink = ip->i_e2fs_nlink;
1.83      mrg       306:        vap->va_uid = ip->i_uid;
                    307:        vap->va_gid = ip->i_gid;
1.44      fvdl      308:        vap->va_rdev = (dev_t)fs2h32(ip->i_din.e2fs_din->e2di_rdev);
1.37      chs       309:        vap->va_size = vp->v_size;
1.1       bouyer    310:        vap->va_atime.tv_sec = ip->i_e2fs_atime;
                    311:        vap->va_atime.tv_nsec = 0;
                    312:        vap->va_mtime.tv_sec = ip->i_e2fs_mtime;
                    313:        vap->va_mtime.tv_nsec = 0;
                    314:        vap->va_ctime.tv_sec = ip->i_e2fs_ctime;
                    315:        vap->va_ctime.tv_nsec = 0;
                    316: #ifdef EXT2FS_SYSTEM_FLAGS
                    317:        vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0;
                    318:        vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
                    319: #else
                    320:        vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? UF_APPEND : 0;
                    321:        vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? UF_IMMUTABLE : 0;
                    322: #endif
                    323:        vap->va_gen = ip->i_e2fs_gen;
                    324:        /* this doesn't belong here */
                    325:        if (vp->v_type == VBLK)
                    326:                vap->va_blocksize = BLKDEV_IOSIZE;
                    327:        else if (vp->v_type == VCHR)
                    328:                vap->va_blocksize = MAXBSIZE;
                    329:        else
                    330:                vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
1.105     jakllsch  331:        vap->va_bytes = dbtob(ext2fs_nblock(ip));
1.1       bouyer    332:        vap->va_type = vp->v_type;
                    333:        vap->va_filerev = ip->i_modrev;
                    334:        return (0);
                    335: }
                    336:
                    337: /*
                    338:  * Set attribute vnode op. called from several syscalls
                    339:  */
                    340: int
1.61      xtraeme   341: ext2fs_setattr(void *v)
1.1       bouyer    342: {
                    343:        struct vop_setattr_args /* {
                    344:                struct vnode *a_vp;
                    345:                struct vattr *a_vap;
1.65      elad      346:                kauth_cred_t a_cred;
1.1       bouyer    347:        } */ *ap = v;
1.8       fvdl      348:        struct vattr *vap = ap->a_vap;
                    349:        struct vnode *vp = ap->a_vp;
                    350:        struct inode *ip = VTOI(vp);
1.65      elad      351:        kauth_cred_t cred = ap->a_cred;
1.76      pooka     352:        struct lwp *l = curlwp;
1.1       bouyer    353:        int error;
1.102     elad      354:        kauth_action_t action = KAUTH_VNODE_WRITE_FLAGS;
                    355:        bool changing_sysflags = false;
1.1       bouyer    356:
                    357:        /*
                    358:         * Check for unsettable attributes.
                    359:         */
1.5       christos  360:        if ((vap->va_type != VNON) || (vap->va_nlink != (nlink_t)VNOVAL) ||
1.24      thorpej   361:            (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
                    362:            (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
                    363:            ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
1.1       bouyer    364:                return (EINVAL);
                    365:        }
                    366:        if (vap->va_flags != VNOVAL) {
1.8       fvdl      367:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    368:                        return (EROFS);
1.102     elad      369:
                    370:                /*
                    371:                 * Check if we're allowed to change the flags.
                    372:                 * If EXT2FS_SYSTEM_FLAGS is set, then the flags are treated
                    373:                 * as system flags, otherwise they're considered to be user
                    374:                 * flags.
                    375:                 */
                    376: #ifdef EXT2FS_SYSTEM_FLAGS
                    377:                /* Indicate we're changing system flags if we are. */
                    378:                if ((vap->va_flags & SF_APPEND) ||
                    379:                     (vap->va_flags & SF_IMMUTABLE)) {
                    380:                        action |= KAUTH_VNODE_WRITE_SYSFLAGS;
                    381:                        changing_sysflags = true;
                    382:                }
                    383:
                    384:                /* Indicate the node has system flags if it does. */
                    385:                if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE)) {
                    386:                        action |= KAUTH_VNODE_HAS_SYSFLAGS;
                    387:                }
                    388: #endif /* EXT2FS_SYSTEM_FLAGS */
                    389:
                    390:                error = kauth_authorize_vnode(cred, action, vp, NULL,
                    391:                    genfs_can_chflags(cred, vp->v_type, ip->i_uid,
                    392:                    changing_sysflags));
                    393:                if (error)
1.1       bouyer    394:                        return (error);
1.102     elad      395:
1.1       bouyer    396: #ifdef EXT2FS_SYSTEM_FLAGS
1.102     elad      397:                ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
                    398:                ip->i_e2fs_flags |=
                    399:                    (vap->va_flags & SF_APPEND) ?  EXT2_APPEND : 0 |
                    400:                    (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
1.1       bouyer    401: #else
                    402:                ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
1.24      thorpej   403:                ip->i_e2fs_flags |=
                    404:                    (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
                    405:                    (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
1.1       bouyer    406: #endif
                    407:                ip->i_flag |= IN_CHANGE;
                    408:                if (vap->va_flags & (IMMUTABLE | APPEND))
                    409:                        return (0);
                    410:        }
                    411:        if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE))
                    412:                return (EPERM);
                    413:        /*
                    414:         * Go through the fields and update iff not VNOVAL.
                    415:         */
                    416:        if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
1.8       fvdl      417:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    418:                        return (EROFS);
1.67      ad        419:                error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
1.1       bouyer    420:                if (error)
                    421:                        return (error);
                    422:        }
                    423:        if (vap->va_size != VNOVAL) {
1.8       fvdl      424:                /*
                    425:                 * Disallow write attempts on read-only file systems;
                    426:                 * unless the file is a socket, fifo, or a block or
                    427:                 * character device resident on the file system.
                    428:                 */
                    429:                switch (vp->v_type) {
                    430:                case VDIR:
1.1       bouyer    431:                        return (EISDIR);
1.8       fvdl      432:                case VLNK:
                    433:                case VREG:
                    434:                        if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    435:                                return (EROFS);
                    436:                default:
                    437:                        break;
                    438:                }
1.77      pooka     439:                error = ext2fs_truncate(vp, vap->va_size, 0, cred);
1.1       bouyer    440:                if (error)
                    441:                        return (error);
                    442:        }
                    443:        ip = VTOI(vp);
                    444:        if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
1.8       fvdl      445:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    446:                        return (EROFS);
1.102     elad      447:                error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
                    448:                    NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid,
                    449:                    cred));
1.86      elad      450:                if (error)
1.1       bouyer    451:                        return (error);
                    452:                if (vap->va_atime.tv_sec != VNOVAL)
                    453:                        if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
                    454:                                ip->i_flag |= IN_ACCESS;
1.101     christos  455:                if (vap->va_mtime.tv_sec != VNOVAL) {
1.1       bouyer    456:                        ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.101     christos  457:                        if (vp->v_mount->mnt_flag & MNT_RELATIME)
                    458:                                ip->i_flag |= IN_ACCESS;
                    459:                }
1.63      yamt      460:                error = ext2fs_update(vp, &vap->va_atime, &vap->va_mtime,
1.26      perseant  461:                        UPDATE_WAIT);
1.1       bouyer    462:                if (error)
                    463:                        return (error);
                    464:        }
                    465:        error = 0;
1.8       fvdl      466:        if (vap->va_mode != (mode_t)VNOVAL) {
                    467:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    468:                        return (EROFS);
1.67      ad        469:                error = ext2fs_chmod(vp, (int)vap->va_mode, cred, l);
1.8       fvdl      470:        }
1.42      jdolecek  471:        VN_KNOTE(vp, NOTE_ATTRIB);
1.1       bouyer    472:        return (error);
                    473: }
                    474:
                    475: /*
                    476:  * Change the mode on a file.
                    477:  * Inode must be locked before calling.
                    478:  */
                    479: static int
1.67      ad        480: ext2fs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
1.1       bouyer    481: {
1.25      augustss  482:        struct inode *ip = VTOI(vp);
1.84      elad      483:        int error;
1.1       bouyer    484:
1.102     elad      485:        error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
                    486:            NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid,
                    487:            mode));
1.84      elad      488:        if (error)
1.1       bouyer    489:                return (error);
1.84      elad      490:
1.1       bouyer    491:        ip->i_e2fs_mode &= ~ALLPERMS;
                    492:        ip->i_e2fs_mode |= (mode & ALLPERMS);
                    493:        ip->i_flag |= IN_CHANGE;
                    494:        return (0);
                    495: }
                    496:
                    497: /*
                    498:  * Perform chown operation on inode ip;
                    499:  * inode must be locked prior to call.
                    500:  */
                    501: static int
1.65      elad      502: ext2fs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
1.67      ad        503:                struct lwp *l)
1.1       bouyer    504: {
1.25      augustss  505:        struct inode *ip = VTOI(vp);
1.1       bouyer    506:        uid_t ouid;
                    507:        gid_t ogid;
1.84      elad      508:        int error;
1.1       bouyer    509:
                    510:        if (uid == (uid_t)VNOVAL)
1.83      mrg       511:                uid = ip->i_uid;
1.1       bouyer    512:        if (gid == (gid_t)VNOVAL)
1.83      mrg       513:                gid = ip->i_gid;
1.84      elad      514:
1.102     elad      515:        error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
                    516:            NULL, genfs_can_chown(cred, ip->i_uid, ip->i_gid, uid, gid));
1.84      elad      517:        if (error)
1.1       bouyer    518:                return (error);
1.84      elad      519:
1.83      mrg       520:        ogid = ip->i_gid;
                    521:        ouid = ip->i_uid;
1.1       bouyer    522:
1.83      mrg       523:        ip->i_e2fs_gid = gid & 0xffff;
                    524:        ip->i_e2fs_uid = uid & 0xffff;
                    525:        if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0) {
                    526:                ip->i_e2fs_gid_high = (gid >> 16) & 0xffff;
                    527:                ip->i_e2fs_uid_high = (uid >> 16) & 0xffff;
                    528:        } else {
                    529:                ip->i_e2fs_gid_high = 0;
                    530:                ip->i_e2fs_uid_high = 0;
                    531:        }
1.91      pooka     532:        if (ouid != uid || ogid != gid) {
                    533:                ext2fs_set_inode_guid(ip);
1.1       bouyer    534:                ip->i_flag |= IN_CHANGE;
1.91      pooka     535:        }
1.102     elad      536:        if (ouid != uid && (ip->i_e2fs_mode & ISUID) &&
                    537:            kauth_authorize_vnode(cred, KAUTH_VNODE_RETAIN_SUID,
                    538:            vp, NULL, EPERM) != 0)
1.1       bouyer    539:                ip->i_e2fs_mode &= ~ISUID;
1.102     elad      540:        if (ogid != gid && (ip->i_e2fs_mode & ISGID) &&
                    541:            kauth_authorize_vnode(cred, KAUTH_VNODE_RETAIN_SGID,
                    542:            vp, NULL, EPERM) != 0)
1.1       bouyer    543:                ip->i_e2fs_mode &= ~ISGID;
                    544:        return (0);
                    545: }
                    546:
                    547: int
1.61      xtraeme   548: ext2fs_remove(void *v)
1.1       bouyer    549: {
                    550:        struct vop_remove_args /* {
                    551:                struct vnode *a_dvp;
                    552:                struct vnode *a_vp;
                    553:                struct componentname *a_cnp;
                    554:        } */ *ap = v;
1.8       fvdl      555:        struct inode *ip;
                    556:        struct vnode *vp = ap->a_vp;
                    557:        struct vnode *dvp = ap->a_dvp;
1.100     dholland  558:        struct ufs_lookup_results *ulr;
1.1       bouyer    559:        int error;
                    560:
1.100     dholland  561:        /* XXX should handle this material another way */
                    562:        ulr = &VTOI(dvp)->i_crap;
                    563:        UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
                    564:
1.1       bouyer    565:        ip = VTOI(vp);
1.2       fvdl      566:        if (vp->v_type == VDIR ||
                    567:                (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
1.1       bouyer    568:                (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) {
                    569:                error = EPERM;
1.43      jdolecek  570:        } else {
1.100     dholland  571:                error = ext2fs_dirremove(dvp, ulr, ap->a_cnp);
1.43      jdolecek  572:                if (error == 0) {
                    573:                        ip->i_e2fs_nlink--;
                    574:                        ip->i_flag |= IN_CHANGE;
                    575:                }
1.1       bouyer    576:        }
1.43      jdolecek  577:
1.42      jdolecek  578:        VN_KNOTE(vp, NOTE_DELETE);
                    579:        VN_KNOTE(dvp, NOTE_WRITE);
1.1       bouyer    580:        if (dvp == vp)
                    581:                vrele(vp);
                    582:        else
                    583:                vput(vp);
                    584:        vput(dvp);
                    585:        return (error);
                    586: }
                    587:
                    588: /*
1.98      rmind     589:  * ext2fs_link: create hard link.
1.1       bouyer    590:  */
                    591: int
1.61      xtraeme   592: ext2fs_link(void *v)
1.1       bouyer    593: {
                    594:        struct vop_link_args /* {
                    595:                struct vnode *a_dvp;
                    596:                struct vnode *a_vp;
                    597:                struct componentname *a_cnp;
                    598:        } */ *ap = v;
1.8       fvdl      599:        struct vnode *dvp = ap->a_dvp;
                    600:        struct vnode *vp = ap->a_vp;
                    601:        struct componentname *cnp = ap->a_cnp;
                    602:        struct inode *ip;
1.1       bouyer    603:        int error;
1.100     dholland  604:        struct ufs_lookup_results *ulr;
1.1       bouyer    605:
1.98      rmind     606:        KASSERT(dvp != vp);
                    607:        KASSERT(vp->v_type != VDIR);
                    608:        KASSERT(dvp->v_mount == vp->v_mount);
                    609:
1.100     dholland  610:        /* XXX should handle this material another way */
                    611:        ulr = &VTOI(dvp)->i_crap;
                    612:        UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
                    613:
1.98      rmind     614:        error = vn_lock(vp, LK_EXCLUSIVE);
                    615:        if (error) {
1.1       bouyer    616:                VOP_ABORTOP(dvp, cnp);
                    617:                goto out2;
                    618:        }
                    619:        ip = VTOI(vp);
                    620:        if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
                    621:                VOP_ABORTOP(dvp, cnp);
                    622:                error = EMLINK;
                    623:                goto out1;
                    624:        }
                    625:        if (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) {
                    626:                VOP_ABORTOP(dvp, cnp);
                    627:                error = EPERM;
                    628:                goto out1;
                    629:        }
                    630:        ip->i_e2fs_nlink++;
                    631:        ip->i_flag |= IN_CHANGE;
1.63      yamt      632:        error = ext2fs_update(vp, NULL, NULL, UPDATE_WAIT);
1.1       bouyer    633:        if (!error)
1.100     dholland  634:                error = ext2fs_direnter(ip, dvp, ulr, cnp);
1.1       bouyer    635:        if (error) {
                    636:                ip->i_e2fs_nlink--;
                    637:                ip->i_flag |= IN_CHANGE;
                    638:        }
                    639: out1:
1.98      rmind     640:        VOP_UNLOCK(vp);
1.1       bouyer    641: out2:
1.42      jdolecek  642:        VN_KNOTE(vp, NOTE_LINK);
                    643:        VN_KNOTE(dvp, NOTE_WRITE);
1.1       bouyer    644:        vput(dvp);
                    645:        return (error);
                    646: }
                    647:
                    648: /*
                    649:  * Mkdir system call
                    650:  */
                    651: int
1.61      xtraeme   652: ext2fs_mkdir(void *v)
1.1       bouyer    653: {
1.110   ! hannken   654:        struct vop_mkdir_v3_args /* {
1.1       bouyer    655:                struct vnode *a_dvp;
                    656:                struct vnode **a_vpp;
                    657:                struct componentname *a_cnp;
                    658:                struct vattr *a_vap;
                    659:        } */ *ap = v;
1.55      mycroft   660:        struct vnode            *dvp = ap->a_dvp;
                    661:        struct vattr            *vap = ap->a_vap;
                    662:        struct componentname    *cnp = ap->a_cnp;
                    663:        struct inode            *ip, *dp = VTOI(dvp);
                    664:        struct vnode            *tvp;
1.4       bouyer    665:        struct ext2fs_dirtemplate dirtemplate;
1.55      mycroft   666:        int                     error, dmode;
1.100     dholland  667:        struct ufs_lookup_results *ulr;
                    668:
                    669:        /* XXX should handle this material another way */
                    670:        ulr = &VTOI(dvp)->i_crap;
                    671:        UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
1.1       bouyer    672:
                    673:        if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
                    674:                error = EMLINK;
                    675:                goto out;
                    676:        }
                    677:        dmode = vap->va_mode & ACCESSPERMS;
                    678:        dmode |= IFDIR;
                    679:        /*
                    680:         * Must simulate part of ext2fs_makeinode here to acquire the inode,
                    681:         * but not have it entered in the parent directory. The entry is
                    682:         * made later after writing "." and ".." entries.
                    683:         */
1.63      yamt      684:        if ((error = ext2fs_valloc(dvp, dmode, cnp->cn_cred, &tvp)) != 0)
1.1       bouyer    685:                goto out;
                    686:        ip = VTOI(tvp);
1.83      mrg       687:        ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
                    688:        ip->i_e2fs_uid = ip->i_uid & 0xffff;
1.1       bouyer    689:        ip->i_e2fs_gid = dp->i_e2fs_gid;
1.83      mrg       690:        if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0) {
                    691:                ip->i_e2fs_uid_high = (ip->i_uid >> 16) & 0xffff;
                    692:                ip->i_e2fs_gid_high = dp->i_e2fs_gid_high;
                    693:        } else {
                    694:                ip->i_e2fs_uid_high = 0;
                    695:                ip->i_e2fs_gid_high = 0;
                    696:        }
                    697:        ip->i_gid = ip->i_e2fs_gid | (ip->i_e2fs_gid_high << 16);
1.1       bouyer    698:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
                    699:        ip->i_e2fs_mode = dmode;
                    700:        tvp->v_type = VDIR;     /* Rest init'd in getnewvnode(). */
                    701:        ip->i_e2fs_nlink = 2;
                    702:
                    703:        /*
                    704:         * Bump link count in parent directory
                    705:         * to reflect work done below.  Should
                    706:         * be done before reference is created
                    707:         * so reparation is possible if we crash.
                    708:         */
                    709:        dp->i_e2fs_nlink++;
                    710:        dp->i_flag |= IN_CHANGE;
1.63      yamt      711:        if ((error = ext2fs_update(dvp, NULL, NULL, UPDATE_DIROP)) != 0)
1.1       bouyer    712:                goto bad;
                    713:
                    714:        /* Initialize directory with "." and ".." from static template. */
1.13      perry     715:        memset(&dirtemplate, 0, sizeof(dirtemplate));
1.4       bouyer    716:        dirtemplate.dot_ino = h2fs32(ip->i_number);
                    717:        dirtemplate.dot_reclen = h2fs16(12);
1.22      bouyer    718:        dirtemplate.dot_namlen = 1;
                    719:        if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
                    720:            (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
1.23      bouyer    721:                dirtemplate.dot_type = EXT2_FT_DIR;
1.22      bouyer    722:        }
1.4       bouyer    723:        dirtemplate.dot_name[0] = '.';
                    724:        dirtemplate.dotdot_ino = h2fs32(dp->i_number);
                    725:     dirtemplate.dotdot_reclen = h2fs16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12);
1.22      bouyer    726:        dirtemplate.dotdot_namlen = 2;
                    727:        if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
                    728:            (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
1.23      bouyer    729:                dirtemplate.dotdot_type = EXT2_FT_DIR;
1.22      bouyer    730:        }
1.4       bouyer    731:        dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
1.74      christos  732:        error = vn_rdwr(UIO_WRITE, tvp, (void *)&dirtemplate,
1.1       bouyer    733:            sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
1.56      skrll     734:            IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (size_t *)0, NULL);
1.1       bouyer    735:        if (error) {
                    736:                dp->i_e2fs_nlink--;
                    737:                dp->i_flag |= IN_CHANGE;
                    738:                goto bad;
                    739:        }
1.55      mycroft   740:        if (VTOI(dvp)->i_e2fs->e2fs_bsize > dvp->v_mount->mnt_stat.f_bsize)
1.1       bouyer    741:                panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */
                    742:        else {
1.58      ws        743:                error = ext2fs_setsize(ip, VTOI(dvp)->i_e2fs->e2fs_bsize);
                    744:                if (error) {
                    745:                        dp->i_e2fs_nlink--;
                    746:                        dp->i_flag |= IN_CHANGE;
                    747:                        goto bad;
                    748:                }
1.1       bouyer    749:                ip->i_flag |= IN_CHANGE;
1.60      kml       750:                uvm_vnp_setsize(tvp, ext2fs_size(ip));
1.1       bouyer    751:        }
                    752:
                    753:        /* Directory set up, now install it's entry in the parent directory. */
1.100     dholland  754:        error = ext2fs_direnter(ip, dvp, ulr, cnp);
1.1       bouyer    755:        if (error != 0) {
                    756:                dp->i_e2fs_nlink--;
                    757:                dp->i_flag |= IN_CHANGE;
                    758:        }
                    759: bad:
                    760:        /*
1.63      yamt      761:         * No need to do an explicit ext2fs_truncate here, vrele will do this
1.1       bouyer    762:         * for us because we set the link count to 0.
                    763:         */
                    764:        if (error) {
                    765:                ip->i_e2fs_nlink = 0;
                    766:                ip->i_flag |= IN_CHANGE;
                    767:                vput(tvp);
1.42      jdolecek  768:        } else {
                    769:                VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1.110   ! hannken   770:                VOP_UNLOCK(tvp);
1.1       bouyer    771:                *ap->a_vpp = tvp;
1.42      jdolecek  772:        }
1.1       bouyer    773: out:
                    774:        return (error);
                    775: }
                    776:
                    777: /*
                    778:  * Rmdir system call.
                    779:  */
                    780: int
1.61      xtraeme   781: ext2fs_rmdir(void *v)
1.1       bouyer    782: {
                    783:        struct vop_rmdir_args /* {
                    784:                struct vnode *a_dvp;
                    785:                struct vnode *a_vp;
                    786:                struct componentname *a_cnp;
                    787:        } */ *ap = v;
1.25      augustss  788:        struct vnode *vp = ap->a_vp;
                    789:        struct vnode *dvp = ap->a_dvp;
                    790:        struct componentname *cnp = ap->a_cnp;
                    791:        struct inode *ip, *dp;
1.1       bouyer    792:        int error;
1.100     dholland  793:        struct ufs_lookup_results *ulr;
1.1       bouyer    794:
                    795:        ip = VTOI(vp);
                    796:        dp = VTOI(dvp);
1.100     dholland  797:
                    798:        /* XXX should handle this material another way */
                    799:        ulr = &dp->i_crap;
                    800:        UFS_CHECK_CRAPCOUNTER(dp);
                    801:
1.1       bouyer    802:        /*
                    803:         * No rmdir "." please.
                    804:         */
                    805:        if (dp == ip) {
                    806:                vrele(dvp);
                    807:                vput(vp);
                    808:                return (EINVAL);
                    809:        }
                    810:        /*
                    811:         * Verify the directory is empty (and valid).
                    812:         * (Rmdir ".." won't be valid since
                    813:         *  ".." will contain a reference to
                    814:         *  the current directory and thus be
                    815:         *  non-empty.)
                    816:         */
                    817:        error = 0;
                    818:        if (ip->i_e2fs_nlink != 2 ||
                    819:            !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
                    820:                error = ENOTEMPTY;
                    821:                goto out;
                    822:        }
                    823:        if ((dp->i_e2fs_flags & EXT2_APPEND) ||
                    824:                                 (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) {
                    825:                error = EPERM;
                    826:                goto out;
                    827:        }
                    828:        /*
                    829:         * Delete reference to directory before purging
                    830:         * inode.  If we crash in between, the directory
                    831:         * will be reattached to lost+found,
                    832:         */
1.100     dholland  833:        error = ext2fs_dirremove(dvp, ulr, cnp);
1.1       bouyer    834:        if (error != 0)
                    835:                goto out;
                    836:        dp->i_e2fs_nlink--;
                    837:        dp->i_flag |= IN_CHANGE;
1.42      jdolecek  838:        VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1.1       bouyer    839:        cache_purge(dvp);
                    840:        vput(dvp);
                    841:        dvp = NULL;
                    842:        /*
                    843:         * Truncate inode.  The only stuff left
                    844:         * in the directory is "." and "..".  The
                    845:         * "." reference is inconsequential since
                    846:         * we're quashing it.  The ".." reference
                    847:         * has already been adjusted above.  We've
                    848:         * removed the "." reference and the reference
                    849:         * in the parent directory, but there may be
                    850:         * other hard links so decrement by 2 and
                    851:         * worry about them later.
                    852:         */
                    853:        ip->i_e2fs_nlink -= 2;
1.77      pooka     854:        error = ext2fs_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred);
1.1       bouyer    855:        cache_purge(ITOV(ip));
                    856: out:
1.42      jdolecek  857:        VN_KNOTE(vp, NOTE_DELETE);
1.1       bouyer    858:        if (dvp)
                    859:                vput(dvp);
                    860:        vput(vp);
                    861:        return (error);
                    862: }
                    863:
                    864: /*
                    865:  * symlink -- make a symbolic link
                    866:  */
                    867: int
1.61      xtraeme   868: ext2fs_symlink(void *v)
1.1       bouyer    869: {
1.110   ! hannken   870:        struct vop_symlink_v3_args /* {
1.1       bouyer    871:                struct vnode *a_dvp;
                    872:                struct vnode **a_vpp;
                    873:                struct componentname *a_cnp;
                    874:                struct vattr *a_vap;
                    875:                char *a_target;
                    876:        } */ *ap = v;
1.55      mycroft   877:        struct vnode    *vp, **vpp;
                    878:        struct inode    *ip;
                    879:        int             len, error;
1.1       bouyer    880:
1.55      mycroft   881:        vpp = ap->a_vpp;
1.1       bouyer    882:        error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
                    883:                              vpp, ap->a_cnp);
                    884:        if (error)
                    885:                return (error);
1.42      jdolecek  886:        VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.1       bouyer    887:        vp = *vpp;
                    888:        len = strlen(ap->a_target);
1.55      mycroft   889:        ip = VTOI(vp);
                    890:        if (len < ip->i_ump->um_maxsymlinklen) {
1.44      fvdl      891:                memcpy((char *)ip->i_din.e2fs_din->e2di_shortlink, ap->a_target, len);
1.58      ws        892:                error = ext2fs_setsize(ip, len);
                    893:                if (error)
                    894:                        goto bad;
1.1       bouyer    895:                ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.101     christos  896:                if (vp->v_mount->mnt_flag & MNT_RELATIME)
                    897:                        ip->i_flag |= IN_ACCESS;
1.60      kml       898:                uvm_vnp_setsize(vp, len);
1.1       bouyer    899:        } else
                    900:                error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1.12      mjacob    901:                    UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred,
1.56      skrll     902:                    (size_t *)0, NULL);
1.58      ws        903: bad:
1.110   ! hannken   904:        VOP_UNLOCK(vp);
1.34      assar     905:        if (error)
1.110   ! hannken   906:                vrele(vp);
1.1       bouyer    907:        return (error);
                    908: }
                    909:
                    910: /*
                    911:  * Return target name of a symbolic link
                    912:  */
                    913: int
1.61      xtraeme   914: ext2fs_readlink(void *v)
1.1       bouyer    915: {
                    916:        struct vop_readlink_args /* {
                    917:                struct vnode *a_vp;
                    918:                struct uio *a_uio;
1.65      elad      919:                kauth_cred_t a_cred;
1.1       bouyer    920:        } */ *ap = v;
1.55      mycroft   921:        struct vnode    *vp = ap->a_vp;
                    922:        struct inode    *ip = VTOI(vp);
                    923:        struct ufsmount *ump = ip->i_ump;
                    924:        int             isize;
1.1       bouyer    925:
1.58      ws        926:        isize = ext2fs_size(ip);
1.55      mycroft   927:        if (isize < ump->um_maxsymlinklen ||
1.105     jakllsch  928:            (ump->um_maxsymlinklen == 0 && ext2fs_nblock(ip) == 0)) {
1.44      fvdl      929:                uiomove((char *)ip->i_din.e2fs_din->e2di_shortlink, isize, ap->a_uio);
1.1       bouyer    930:                return (0);
                    931:        }
                    932:        return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
                    933: }
                    934:
                    935: /*
                    936:  * Advisory record locking support
                    937:  */
                    938: int
1.61      xtraeme   939: ext2fs_advlock(void *v)
1.1       bouyer    940: {
                    941:        struct vop_advlock_args /* {
                    942:                struct vnode *a_vp;
1.74      christos  943:                void * a_id;
1.1       bouyer    944:                int  a_op;
                    945:                struct flock *a_fl;
                    946:                int  a_flags;
                    947:        } */ *ap = v;
1.25      augustss  948:        struct inode *ip = VTOI(ap->a_vp);
1.1       bouyer    949:
1.58      ws        950:        return lf_advlock(ap, &ip->i_lockf, ext2fs_size(ip));
1.1       bouyer    951: }
                    952:
1.63      yamt      953: int
                    954: ext2fs_fsync(void *v)
                    955: {
                    956:        struct vop_fsync_args /* {
                    957:                struct vnode *a_vp;
1.65      elad      958:                kauth_cred_t a_cred;
1.63      yamt      959:                int a_flags;
                    960:                off_t offlo;
                    961:                off_t offhi;
                    962:                struct proc *a_p;
                    963:        } */ *ap = v;
                    964:        struct vnode *vp = ap->a_vp;
                    965:        int wait;
                    966:        int error;
                    967:
                    968:        wait = (ap->a_flags & FSYNC_WAIT) != 0;
1.82      ad        969:
                    970:        if (vp->v_type == VBLK)
1.99      hannken   971:                error = spec_fsync(v);
1.63      yamt      972:        else
1.103     chs       973:                error = vflushbuf(vp, ap->a_flags);
1.99      hannken   974:        if (error == 0 && (ap->a_flags & FSYNC_DATAONLY) == 0)
1.63      yamt      975:                error = ext2fs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0);
                    976:
                    977:        if (error == 0 && ap->a_flags & FSYNC_CACHE) {
                    978:                int l = 0;
                    979:                error = VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE,
1.76      pooka     980:                    curlwp->l_cred);
1.63      yamt      981:        }
                    982:
                    983:        return error;
                    984: }
                    985:
1.1       bouyer    986: /*
                    987:  * Initialize the vnode associated with a new inode, handle aliased
                    988:  * vnodes.
                    989:  */
                    990: int
1.61      xtraeme   991: ext2fs_vinit(struct mount *mntp, int (**specops)(void *),
                    992:        int (**fifoops)(void *), struct vnode **vpp)
1.1       bouyer    993: {
1.66      kardel    994:        struct timeval tv;
1.1       bouyer    995:        struct inode *ip;
1.80      ad        996:        struct vnode *vp;
1.1       bouyer    997:
                    998:        vp = *vpp;
                    999:        ip = VTOI(vp);
                   1000:        switch(vp->v_type = IFTOVT(ip->i_e2fs_mode)) {
                   1001:        case VCHR:
                   1002:        case VBLK:
                   1003:                vp->v_op = specops;
1.80      ad       1004:                spec_node_init(vp, fs2h32(ip->i_din.e2fs_din->e2di_rdev));
1.1       bouyer   1005:                break;
                   1006:        case VFIFO:
                   1007:                vp->v_op = fifoops;
                   1008:                break;
                   1009:        case VNON:
                   1010:        case VBAD:
                   1011:        case VSOCK:
                   1012:        case VLNK:
                   1013:        case VDIR:
                   1014:        case VREG:
                   1015:                break;
                   1016:        }
1.106     dholland 1017:        if (ip->i_number == UFS_ROOTINO)
1.75      ad       1018:                 vp->v_vflag |= VV_ROOT;
1.1       bouyer   1019:        /*
                   1020:         * Initialize modrev times
                   1021:         */
1.66      kardel   1022:        getmicrouptime(&tv);
                   1023:        SETHIGH(ip->i_modrev, tv.tv_sec);
                   1024:        SETLOW(ip->i_modrev, tv.tv_usec * 4294);
1.1       bouyer   1025:        *vpp = vp;
                   1026:        return (0);
                   1027: }
                   1028:
                   1029: /*
                   1030:  * Allocate a new inode.
                   1031:  */
                   1032: int
1.61      xtraeme  1033: ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
                   1034:                struct componentname *cnp)
1.1       bouyer   1035: {
1.25      augustss 1036:        struct inode *ip, *pdir;
1.1       bouyer   1037:        struct vnode *tvp;
1.102     elad     1038:        int error;
1.100     dholland 1039:        struct ufs_lookup_results *ulr;
1.1       bouyer   1040:
                   1041:        pdir = VTOI(dvp);
1.100     dholland 1042:
                   1043:        /* XXX should handle this material another way */
                   1044:        ulr = &pdir->i_crap;
                   1045:        UFS_CHECK_CRAPCOUNTER(pdir);
                   1046:
1.1       bouyer   1047:        *vpp = NULL;
                   1048:        if ((mode & IFMT) == 0)
                   1049:                mode |= IFREG;
                   1050:
1.63      yamt     1051:        if ((error = ext2fs_valloc(dvp, mode, cnp->cn_cred, &tvp)) != 0) {
1.1       bouyer   1052:                return (error);
                   1053:        }
                   1054:        ip = VTOI(tvp);
1.83      mrg      1055:        ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
                   1056:        ip->i_e2fs_uid = ip->i_uid & 0xffff;
1.1       bouyer   1057:        ip->i_e2fs_gid = pdir->i_e2fs_gid;
1.83      mrg      1058:        if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0) {
                   1059:                ip->i_e2fs_uid_high = (ip->i_uid >> 16) & 0xffff;
                   1060:                ip->i_e2fs_gid_high = pdir->i_e2fs_gid_high;
                   1061:        } else {
                   1062:                ip->i_e2fs_uid_high = 0;
                   1063:                ip->i_e2fs_gid_high = 0;
                   1064:        }
                   1065:        ip->i_gid = ip->i_e2fs_gid | (ip->i_e2fs_gid_high << 16);
1.1       bouyer   1066:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
                   1067:        ip->i_e2fs_mode = mode;
                   1068:        tvp->v_type = IFTOVT(mode);     /* Rest init'd in getnewvnode(). */
                   1069:        ip->i_e2fs_nlink = 1;
1.102     elad     1070:
                   1071:        /* Authorize setting SGID if needed. */
                   1072:        if (ip->i_e2fs_mode & ISGID) {
                   1073:                error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
                   1074:                    tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid,
                   1075:                    ip->i_gid, mode));
                   1076:                if (error)
                   1077:                        ip->i_e2fs_mode &= ~ISGID;
                   1078:        }
1.1       bouyer   1079:
                   1080:        /*
                   1081:         * Make sure inode goes to disk before directory entry.
                   1082:         */
1.63      yamt     1083:        if ((error = ext2fs_update(tvp, NULL, NULL, UPDATE_WAIT)) != 0)
1.1       bouyer   1084:                goto bad;
1.100     dholland 1085:        error = ext2fs_direnter(ip, dvp, ulr, cnp);
1.1       bouyer   1086:        if (error != 0)
                   1087:                goto bad;
                   1088:        *vpp = tvp;
                   1089:        return (0);
                   1090:
                   1091: bad:
                   1092:        /*
                   1093:         * Write error occurred trying to update the inode
                   1094:         * or the directory so must deallocate the inode.
                   1095:         */
1.50      dsl      1096:        tvp->v_type = VNON;     /* Stop explosion if VBLK */
1.1       bouyer   1097:        ip->i_e2fs_nlink = 0;
                   1098:        ip->i_flag |= IN_CHANGE;
                   1099:        vput(tvp);
                   1100:        return (error);
                   1101: }
                   1102:
                   1103: /*
                   1104:  * Reclaim an inode so that it can be used for other purposes.
                   1105:  */
                   1106: int
1.61      xtraeme  1107: ext2fs_reclaim(void *v)
1.1       bouyer   1108: {
                   1109:        struct vop_reclaim_args /* {
                   1110:                struct vnode *a_vp;
                   1111:        } */ *ap = v;
1.25      augustss 1112:        struct vnode *vp = ap->a_vp;
1.54      mycroft  1113:        struct inode *ip = VTOI(vp);
                   1114:        int error;
1.45      fvdl     1115:
1.94      hannken  1116:        /*
                   1117:         * The inode must be freed and updated before being removed
                   1118:         * from its hash chain.  Other threads trying to gain a hold
                   1119:         * on the inode will be stalled because it is locked (VI_XLOCK).
                   1120:         */
                   1121:        if (ip->i_omode == 1 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
                   1122:                ext2fs_vfree(vp, ip->i_number, ip->i_e2fs_mode);
1.76      pooka    1123:        if ((error = ufs_reclaim(vp)) != 0)
1.54      mycroft  1124:                return (error);
1.45      fvdl     1125:        if (ip->i_din.e2fs_din != NULL)
                   1126:                pool_put(&ext2fs_dinode_pool, ip->i_din.e2fs_din);
1.73      ad       1127:        genfs_node_destroy(vp);
1.14      thorpej  1128:        pool_put(&ext2fs_inode_pool, vp->v_data);
1.1       bouyer   1129:        vp->v_data = NULL;
                   1130:        return (0);
                   1131: }
                   1132:
                   1133: /* Global vfs data structures for ext2fs. */
1.61      xtraeme  1134: int (**ext2fs_vnodeop_p)(void *);
1.31      jdolecek 1135: const struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = {
1.1       bouyer   1136:        { &vop_default_desc, vn_default_error },
1.8       fvdl     1137:        { &vop_lookup_desc, ext2fs_lookup },            /* lookup */
                   1138:        { &vop_create_desc, ext2fs_create },            /* create */
1.1       bouyer   1139:        { &vop_mknod_desc, ext2fs_mknod },              /* mknod */
                   1140:        { &vop_open_desc, ext2fs_open },                /* open */
                   1141:        { &vop_close_desc, ufs_close },                 /* close */
1.8       fvdl     1142:        { &vop_access_desc, ext2fs_access },            /* access */
                   1143:        { &vop_getattr_desc, ext2fs_getattr },          /* getattr */
                   1144:        { &vop_setattr_desc, ext2fs_setattr },          /* setattr */
1.1       bouyer   1145:        { &vop_read_desc, ext2fs_read },                /* read */
                   1146:        { &vop_write_desc, ext2fs_write },              /* write */
                   1147:        { &vop_ioctl_desc, ufs_ioctl },                 /* ioctl */
1.21      wrstuden 1148:        { &vop_fcntl_desc, ufs_fcntl },                 /* fcntl */
1.1       bouyer   1149:        { &vop_poll_desc, ufs_poll },                   /* poll */
1.42      jdolecek 1150:        { &vop_kqfilter_desc, genfs_kqfilter },         /* kqfilter */
1.8       fvdl     1151:        { &vop_revoke_desc, ufs_revoke },               /* revoke */
1.1       bouyer   1152:        { &vop_mmap_desc, ufs_mmap },                   /* mmap */
                   1153:        { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
                   1154:        { &vop_seek_desc, ufs_seek },                   /* seek */
1.8       fvdl     1155:        { &vop_remove_desc, ext2fs_remove },            /* remove */
1.1       bouyer   1156:        { &vop_link_desc, ext2fs_link },                /* link */
1.8       fvdl     1157:        { &vop_rename_desc, ext2fs_rename },            /* rename */
1.1       bouyer   1158:        { &vop_mkdir_desc, ext2fs_mkdir },              /* mkdir */
                   1159:        { &vop_rmdir_desc, ext2fs_rmdir },              /* rmdir */
1.8       fvdl     1160:        { &vop_symlink_desc, ext2fs_symlink },          /* symlink */
                   1161:        { &vop_readdir_desc, ext2fs_readdir },          /* readdir */
                   1162:        { &vop_readlink_desc, ext2fs_readlink },        /* readlink */
1.1       bouyer   1163:        { &vop_abortop_desc, ufs_abortop },             /* abortop */
1.8       fvdl     1164:        { &vop_inactive_desc, ext2fs_inactive },        /* inactive */
                   1165:        { &vop_reclaim_desc, ext2fs_reclaim },          /* reclaim */
1.1       bouyer   1166:        { &vop_lock_desc, ufs_lock },                   /* lock */
                   1167:        { &vop_unlock_desc, ufs_unlock },               /* unlock */
                   1168:        { &vop_bmap_desc, ext2fs_bmap },                /* bmap */
1.8       fvdl     1169:        { &vop_strategy_desc, ufs_strategy },           /* strategy */
1.1       bouyer   1170:        { &vop_print_desc, ufs_print },                 /* print */
1.8       fvdl     1171:        { &vop_islocked_desc, ufs_islocked },           /* islocked */
                   1172:        { &vop_pathconf_desc, ufs_pathconf },           /* pathconf */
                   1173:        { &vop_advlock_desc, ext2fs_advlock },          /* advlock */
1.1       bouyer   1174:        { &vop_bwrite_desc, vn_bwrite },                /* bwrite */
1.30      chs      1175:        { &vop_getpages_desc, genfs_getpages },         /* getpages */
                   1176:        { &vop_putpages_desc, genfs_putpages },         /* putpages */
                   1177:        { NULL, NULL }
1.1       bouyer   1178: };
1.31      jdolecek 1179: const struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
1.1       bouyer   1180:        { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries };
                   1181:
1.61      xtraeme  1182: int (**ext2fs_specop_p)(void *);
1.31      jdolecek 1183: const struct vnodeopv_entry_desc ext2fs_specop_entries[] = {
1.1       bouyer   1184:        { &vop_default_desc, vn_default_error },
                   1185:        { &vop_lookup_desc, spec_lookup },              /* lookup */
                   1186:        { &vop_create_desc, spec_create },              /* create */
                   1187:        { &vop_mknod_desc, spec_mknod },                /* mknod */
                   1188:        { &vop_open_desc, spec_open },                  /* open */
                   1189:        { &vop_close_desc, ufsspec_close },             /* close */
1.8       fvdl     1190:        { &vop_access_desc, ext2fs_access },            /* access */
                   1191:        { &vop_getattr_desc, ext2fs_getattr },          /* getattr */
                   1192:        { &vop_setattr_desc, ext2fs_setattr },          /* setattr */
1.1       bouyer   1193:        { &vop_read_desc, ufsspec_read },               /* read */
                   1194:        { &vop_write_desc, ufsspec_write },             /* write */
                   1195:        { &vop_ioctl_desc, spec_ioctl },                /* ioctl */
1.21      wrstuden 1196:        { &vop_fcntl_desc, ufs_fcntl },                 /* fcntl */
1.1       bouyer   1197:        { &vop_poll_desc, spec_poll },                  /* poll */
1.42      jdolecek 1198:        { &vop_kqfilter_desc, spec_kqfilter },          /* kqfilter */
1.8       fvdl     1199:        { &vop_revoke_desc, spec_revoke },              /* revoke */
1.1       bouyer   1200:        { &vop_mmap_desc, spec_mmap },                  /* mmap */
                   1201:        { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
                   1202:        { &vop_seek_desc, spec_seek },                  /* seek */
                   1203:        { &vop_remove_desc, spec_remove },              /* remove */
                   1204:        { &vop_link_desc, spec_link },                  /* link */
                   1205:        { &vop_rename_desc, spec_rename },              /* rename */
                   1206:        { &vop_mkdir_desc, spec_mkdir },                /* mkdir */
                   1207:        { &vop_rmdir_desc, spec_rmdir },                /* rmdir */
1.8       fvdl     1208:        { &vop_symlink_desc, spec_symlink },            /* symlink */
                   1209:        { &vop_readdir_desc, spec_readdir },            /* readdir */
                   1210:        { &vop_readlink_desc, spec_readlink },          /* readlink */
                   1211:        { &vop_abortop_desc, spec_abortop },            /* abortop */
                   1212:        { &vop_inactive_desc, ext2fs_inactive },        /* inactive */
                   1213:        { &vop_reclaim_desc, ext2fs_reclaim },          /* reclaim */
1.1       bouyer   1214:        { &vop_lock_desc, ufs_lock },                   /* lock */
                   1215:        { &vop_unlock_desc, ufs_unlock },               /* unlock */
                   1216:        { &vop_bmap_desc, spec_bmap },                  /* bmap */
1.8       fvdl     1217:        { &vop_strategy_desc, spec_strategy },          /* strategy */
1.1       bouyer   1218:        { &vop_print_desc, ufs_print },                 /* print */
1.8       fvdl     1219:        { &vop_islocked_desc, ufs_islocked },           /* islocked */
                   1220:        { &vop_pathconf_desc, spec_pathconf },          /* pathconf */
                   1221:        { &vop_advlock_desc, spec_advlock },            /* advlock */
1.1       bouyer   1222:        { &vop_bwrite_desc, vn_bwrite },                /* bwrite */
1.35      chs      1223:        { &vop_getpages_desc, spec_getpages },          /* getpages */
                   1224:        { &vop_putpages_desc, spec_putpages },          /* putpages */
1.30      chs      1225:        { NULL, NULL }
1.1       bouyer   1226: };
1.31      jdolecek 1227: const struct vnodeopv_desc ext2fs_specop_opv_desc =
1.1       bouyer   1228:        { &ext2fs_specop_p, ext2fs_specop_entries };
                   1229:
1.61      xtraeme  1230: int (**ext2fs_fifoop_p)(void *);
1.31      jdolecek 1231: const struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = {
1.1       bouyer   1232:        { &vop_default_desc, vn_default_error },
1.92      pooka    1233:        { &vop_lookup_desc, vn_fifo_bypass },           /* lookup */
                   1234:        { &vop_create_desc, vn_fifo_bypass },           /* create */
                   1235:        { &vop_mknod_desc, vn_fifo_bypass },            /* mknod */
                   1236:        { &vop_open_desc, vn_fifo_bypass },             /* open */
1.1       bouyer   1237:        { &vop_close_desc, ufsfifo_close },             /* close */
1.8       fvdl     1238:        { &vop_access_desc, ext2fs_access },            /* access */
                   1239:        { &vop_getattr_desc, ext2fs_getattr },          /* getattr */
                   1240:        { &vop_setattr_desc, ext2fs_setattr },          /* setattr */
1.1       bouyer   1241:        { &vop_read_desc, ufsfifo_read },               /* read */
                   1242:        { &vop_write_desc, ufsfifo_write },             /* write */
1.92      pooka    1243:        { &vop_ioctl_desc, vn_fifo_bypass },            /* ioctl */
1.21      wrstuden 1244:        { &vop_fcntl_desc, ufs_fcntl },                 /* fcntl */
1.92      pooka    1245:        { &vop_poll_desc, vn_fifo_bypass },             /* poll */
                   1246:        { &vop_kqfilter_desc, vn_fifo_bypass },         /* kqfilter */
                   1247:        { &vop_revoke_desc, vn_fifo_bypass },           /* revoke */
                   1248:        { &vop_mmap_desc, vn_fifo_bypass },             /* mmap */
1.1       bouyer   1249:        { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
1.92      pooka    1250:        { &vop_seek_desc, vn_fifo_bypass },             /* seek */
                   1251:        { &vop_remove_desc, vn_fifo_bypass },           /* remove */
                   1252:        { &vop_link_desc, vn_fifo_bypass },             /* link */
                   1253:        { &vop_rename_desc, vn_fifo_bypass },           /* rename */
                   1254:        { &vop_mkdir_desc, vn_fifo_bypass },            /* mkdir */
                   1255:        { &vop_rmdir_desc, vn_fifo_bypass },            /* rmdir */
                   1256:        { &vop_symlink_desc, vn_fifo_bypass },          /* symlink */
                   1257:        { &vop_readdir_desc, vn_fifo_bypass },          /* readdir */
                   1258:        { &vop_readlink_desc, vn_fifo_bypass },         /* readlink */
                   1259:        { &vop_abortop_desc, vn_fifo_bypass },          /* abortop */
1.8       fvdl     1260:        { &vop_inactive_desc, ext2fs_inactive },        /* inactive */
                   1261:        { &vop_reclaim_desc, ext2fs_reclaim },          /* reclaim */
1.1       bouyer   1262:        { &vop_lock_desc, ufs_lock },                   /* lock */
                   1263:        { &vop_unlock_desc, ufs_unlock },               /* unlock */
1.92      pooka    1264:        { &vop_bmap_desc, vn_fifo_bypass },             /* bmap */
                   1265:        { &vop_strategy_desc, vn_fifo_bypass },         /* strategy */
1.1       bouyer   1266:        { &vop_print_desc, ufs_print },                 /* print */
1.8       fvdl     1267:        { &vop_islocked_desc, ufs_islocked },           /* islocked */
1.92      pooka    1268:        { &vop_pathconf_desc, vn_fifo_bypass },         /* pathconf */
                   1269:        { &vop_advlock_desc, vn_fifo_bypass },          /* advlock */
1.1       bouyer   1270:        { &vop_bwrite_desc, vn_bwrite },                /* bwrite */
1.92      pooka    1271:        { &vop_putpages_desc, vn_fifo_bypass },         /* putpages */
1.30      chs      1272:        { NULL, NULL }
1.1       bouyer   1273: };
1.31      jdolecek 1274: const struct vnodeopv_desc ext2fs_fifoop_opv_desc =
1.1       bouyer   1275:        { &ext2fs_fifoop_p, ext2fs_fifoop_entries };

CVSweb <webmaster@jp.NetBSD.org>