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

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

CVSweb <webmaster@jp.NetBSD.org>