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

1.74.18.1! yamt        1: /*     $NetBSD: ext2fs_vnops.c,v 1.74 2007/03/04 06:03:43 christos 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:  * 3. All advertising materials mentioning features or use of this software
                     52:  *    must display the following acknowledgement:
1.51      bouyer     53:  *     This product includes software developed by Manuel Bouyer.
                     54:  * 4. The name of the author may not be used to endorse or promote products
                     55:  *    derived from this software without specific prior written permission.
1.1       bouyer     56:  *
1.52      bouyer     57:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     58:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     59:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     60:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     61:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     62:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     63:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     64:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     65:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     66:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1       bouyer     67:  *
                     68:  *     @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
                     69:  * Modified for ext2fs by Manuel Bouyer.
                     70:  */
1.40      lukem      71:
                     72: #include <sys/cdefs.h>
1.74.18.1! yamt       73: __KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.74 2007/03/04 06:03:43 christos Exp $");
1.7       mrg        74:
1.1       bouyer     75: #include <sys/param.h>
                     76: #include <sys/systm.h>
                     77: #include <sys/resourcevar.h>
                     78: #include <sys/kernel.h>
                     79: #include <sys/file.h>
                     80: #include <sys/stat.h>
                     81: #include <sys/buf.h>
                     82: #include <sys/proc.h>
                     83: #include <sys/mount.h>
                     84: #include <sys/namei.h>
                     85: #include <sys/vnode.h>
                     86: #include <sys/lockf.h>
                     87: #include <sys/malloc.h>
1.14      thorpej    88: #include <sys/pool.h>
1.1       bouyer     89: #include <sys/signalvar.h>
1.65      elad       90: #include <sys/kauth.h>
1.1       bouyer     91:
                     92: #include <miscfs/fifofs/fifo.h>
                     93: #include <miscfs/genfs/genfs.h>
                     94: #include <miscfs/specfs/specdev.h>
                     95:
                     96: #include <ufs/ufs/inode.h>
                     97: #include <ufs/ufs/ufs_extern.h>
                     98: #include <ufs/ufs/ufsmount.h>
                     99:
                    100: #include <ufs/ext2fs/ext2fs.h>
                    101: #include <ufs/ext2fs/ext2fs_extern.h>
                    102: #include <ufs/ext2fs/ext2fs_dir.h>
                    103:
1.32      tsutsui   104: extern int prtactive;
1.1       bouyer    105:
1.67      ad        106: static int ext2fs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
1.65      elad      107: static int ext2fs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
1.67      ad        108:                                struct lwp *);
1.1       bouyer    109:
                    110: union _qcvt {
                    111:        int64_t qcvt;
                    112:        int32_t val[2];
                    113: };
1.61      xtraeme   114:
1.1       bouyer    115: #define SETHIGH(q, h) { \
                    116:        union _qcvt tmp; \
                    117:        tmp.qcvt = (q); \
                    118:        tmp.val[_QUAD_HIGHWORD] = (h); \
                    119:        (q) = tmp.qcvt; \
                    120: }
                    121: #define SETLOW(q, l) { \
                    122:        union _qcvt tmp; \
                    123:        tmp.qcvt = (q); \
                    124:        tmp.val[_QUAD_LOWWORD] = (l); \
                    125:        (q) = tmp.qcvt; \
                    126: }
                    127:
                    128: /*
                    129:  * Create a regular file
                    130:  */
                    131: int
1.61      xtraeme   132: ext2fs_create(void *v)
1.1       bouyer    133: {
                    134:        struct vop_create_args /* {
                    135:                struct vnode *a_dvp;
                    136:                struct vnode **a_vpp;
                    137:                struct componentname *a_cnp;
                    138:                struct vattr *a_vap;
                    139:        } */ *ap = v;
1.42      jdolecek  140:        int     error;
                    141:
                    142:        error =
                    143:            ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
                    144:                             ap->a_dvp, ap->a_vpp, ap->a_cnp);
                    145:
                    146:        if (error)
                    147:                return (error);
                    148:        VN_KNOTE(ap->a_dvp, NOTE_WRITE);
                    149:        return (0);
1.1       bouyer    150: }
                    151:
                    152: /*
                    153:  * Mknod vnode call
                    154:  */
                    155: /* ARGSUSED */
                    156: int
1.61      xtraeme   157: ext2fs_mknod(void *v)
1.1       bouyer    158: {
                    159:        struct vop_mknod_args /* {
                    160:                struct vnode *a_dvp;
                    161:                struct vnode **a_vpp;
                    162:                struct componentname *a_cnp;
                    163:                struct vattr *a_vap;
                    164:        } */ *ap = v;
1.25      augustss  165:        struct vattr *vap = ap->a_vap;
                    166:        struct vnode **vpp = ap->a_vpp;
                    167:        struct inode *ip;
1.1       bouyer    168:        int error;
1.59      perry     169:        struct mount    *mp;
1.34      assar     170:        ino_t           ino;
1.1       bouyer    171:
1.8       fvdl      172:        if ((error = ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
                    173:                    ap->a_dvp, vpp, ap->a_cnp)) != 0)
1.1       bouyer    174:                return (error);
1.42      jdolecek  175:        VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.1       bouyer    176:        ip = VTOI(*vpp);
1.34      assar     177:        mp  = (*vpp)->v_mount;
                    178:        ino = ip->i_number;
1.1       bouyer    179:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
                    180:        if (vap->va_rdev != VNOVAL) {
                    181:                /*
                    182:                 * Want to be able to use this to make badblock
                    183:                 * inodes, so don't truncate the dev number.
                    184:                 */
1.44      fvdl      185:                ip->i_din.e2fs_din->e2di_rdev = h2fs32(vap->va_rdev);
1.1       bouyer    186:        }
                    187:        /*
                    188:         * Remove inode so that it will be reloaded by VFS_VGET and
                    189:         * checked to see if it is an alias of an existing entry in
                    190:         * the inode cache.
                    191:         */
                    192:        vput(*vpp);
                    193:        (*vpp)->v_type = VNON;
                    194:        vgone(*vpp);
1.47      thorpej   195:        error = VFS_VGET(mp, ino, vpp);
1.34      assar     196:        if (error != 0) {
                    197:                *vpp = NULL;
                    198:                return (error);
                    199:        }
1.1       bouyer    200:        return (0);
                    201: }
                    202:
                    203: /*
                    204:  * Open called.
                    205:  *
                    206:  * Just check the APPEND flag.
                    207:  */
                    208: /* ARGSUSED */
                    209: int
1.61      xtraeme   210: ext2fs_open(void *v)
1.1       bouyer    211: {
                    212:        struct vop_open_args /* {
                    213:                struct vnode *a_vp;
                    214:                int  a_mode;
1.65      elad      215:                kauth_cred_t a_cred;
1.64      christos  216:                struct lwp *a_l;
1.1       bouyer    217:        } */ *ap = v;
                    218:
                    219:        /*
                    220:         * Files marked append-only must be opened for appending.
                    221:         */
                    222:        if ((VTOI(ap->a_vp)->i_e2fs_flags & EXT2_APPEND) &&
                    223:                (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
                    224:                return (EPERM);
                    225:        return (0);
                    226: }
                    227:
                    228: int
1.61      xtraeme   229: ext2fs_access(void *v)
1.1       bouyer    230: {
                    231:        struct vop_access_args /* {
                    232:                struct vnode *a_vp;
                    233:                int  a_mode;
1.65      elad      234:                kauth_cred_t a_cred;
1.64      christos  235:                struct lwp *a_l;
1.1       bouyer    236:        } */ *ap = v;
1.8       fvdl      237:        struct vnode *vp = ap->a_vp;
                    238:        struct inode *ip = VTOI(vp);
1.1       bouyer    239:        mode_t mode = ap->a_mode;
                    240:
1.8       fvdl      241:        /*
                    242:         * Disallow write attempts on read-only file systems;
                    243:         * unless the file is a socket, fifo, or a block or
                    244:         * character device resident on the file system.
                    245:         */
                    246:        if (mode & VWRITE) {
                    247:                switch (vp->v_type) {
                    248:                case VDIR:
                    249:                case VLNK:
                    250:                case VREG:
                    251:                        if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    252:                                return (EROFS);
                    253:                        break;
                    254:                default:
                    255:                        break;
                    256:                }
1.1       bouyer    257:        }
                    258:
                    259:        /* If immutable bit set, nobody gets to write it. */
                    260:        if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE))
                    261:                return (EPERM);
                    262:
                    263:        return (vaccess(vp->v_type, ip->i_e2fs_mode & ALLPERMS,
                    264:                        ip->i_e2fs_uid, ip->i_e2fs_gid, mode, ap->a_cred));
                    265: }
                    266:
                    267: /* ARGSUSED */
                    268: int
1.61      xtraeme   269: ext2fs_getattr(void *v)
1.1       bouyer    270: {
                    271:        struct vop_getattr_args /* {
                    272:                struct vnode *a_vp;
                    273:                struct vattr *a_vap;
1.65      elad      274:                kauth_cred_t a_cred;
1.64      christos  275:                struct lwp *a_l;
1.1       bouyer    276:        } */ *ap = v;
1.25      augustss  277:        struct vnode *vp = ap->a_vp;
                    278:        struct inode *ip = VTOI(vp);
                    279:        struct vattr *vap = ap->a_vap;
1.1       bouyer    280:
1.62      christos  281:        EXT2FS_ITIMES(ip, NULL, NULL, NULL);
1.1       bouyer    282:        /*
                    283:         * Copy from inode table
                    284:         */
                    285:        vap->va_fsid = ip->i_dev;
                    286:        vap->va_fileid = ip->i_number;
                    287:        vap->va_mode = ip->i_e2fs_mode & ALLPERMS;
                    288:        vap->va_nlink = ip->i_e2fs_nlink;
                    289:        vap->va_uid = ip->i_e2fs_uid;
                    290:        vap->va_gid = ip->i_e2fs_gid;
1.44      fvdl      291:        vap->va_rdev = (dev_t)fs2h32(ip->i_din.e2fs_din->e2di_rdev);
1.37      chs       292:        vap->va_size = vp->v_size;
1.1       bouyer    293:        vap->va_atime.tv_sec = ip->i_e2fs_atime;
                    294:        vap->va_atime.tv_nsec = 0;
                    295:        vap->va_mtime.tv_sec = ip->i_e2fs_mtime;
                    296:        vap->va_mtime.tv_nsec = 0;
                    297:        vap->va_ctime.tv_sec = ip->i_e2fs_ctime;
                    298:        vap->va_ctime.tv_nsec = 0;
                    299: #ifdef EXT2FS_SYSTEM_FLAGS
                    300:        vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0;
                    301:        vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
                    302: #else
                    303:        vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? UF_APPEND : 0;
                    304:        vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? UF_IMMUTABLE : 0;
                    305: #endif
                    306:        vap->va_gen = ip->i_e2fs_gen;
                    307:        /* this doesn't belong here */
                    308:        if (vp->v_type == VBLK)
                    309:                vap->va_blocksize = BLKDEV_IOSIZE;
                    310:        else if (vp->v_type == VCHR)
                    311:                vap->va_blocksize = MAXBSIZE;
                    312:        else
                    313:                vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
1.8       fvdl      314:        vap->va_bytes = dbtob((u_quad_t)ip->i_e2fs_nblock);
1.1       bouyer    315:        vap->va_type = vp->v_type;
                    316:        vap->va_filerev = ip->i_modrev;
                    317:        return (0);
                    318: }
                    319:
                    320: /*
                    321:  * Set attribute vnode op. called from several syscalls
                    322:  */
                    323: int
1.61      xtraeme   324: ext2fs_setattr(void *v)
1.1       bouyer    325: {
                    326:        struct vop_setattr_args /* {
                    327:                struct vnode *a_vp;
                    328:                struct vattr *a_vap;
1.65      elad      329:                kauth_cred_t a_cred;
1.64      christos  330:                struct lwp *a_l;
1.1       bouyer    331:        } */ *ap = v;
1.8       fvdl      332:        struct vattr *vap = ap->a_vap;
                    333:        struct vnode *vp = ap->a_vp;
                    334:        struct inode *ip = VTOI(vp);
1.65      elad      335:        kauth_cred_t cred = ap->a_cred;
1.64      christos  336:        struct lwp *l = ap->a_l;
1.1       bouyer    337:        int error;
                    338:
                    339:        /*
                    340:         * Check for unsettable attributes.
                    341:         */
1.5       christos  342:        if ((vap->va_type != VNON) || (vap->va_nlink != (nlink_t)VNOVAL) ||
1.24      thorpej   343:            (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
                    344:            (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
                    345:            ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
1.1       bouyer    346:                return (EINVAL);
                    347:        }
                    348:        if (vap->va_flags != VNOVAL) {
1.8       fvdl      349:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    350:                        return (EROFS);
1.65      elad      351:                if (kauth_cred_geteuid(cred) != ip->i_e2fs_uid &&
1.67      ad        352:                    (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
1.72      elad      353:                    NULL)))
1.1       bouyer    354:                        return (error);
                    355: #ifdef EXT2FS_SYSTEM_FLAGS
1.72      elad      356:                if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
                    357:                    NULL) == 0) {
1.24      thorpej   358:                        if ((ip->i_e2fs_flags &
1.71      elad      359:                            (EXT2_APPEND | EXT2_IMMUTABLE)) &&
                    360:                            kauth_authorize_system(l->l_cred,
                    361:                             KAUTH_SYSTEM_CHSYSFLAGS, 0, NULL, NULL, NULL))
1.1       bouyer    362:                                return (EPERM);
                    363:                        ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
1.24      thorpej   364:                        ip->i_e2fs_flags |=
                    365:                            (vap->va_flags & SF_APPEND) ?  EXT2_APPEND : 0 |
                    366:                            (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
                    367:                } else
1.1       bouyer    368:                        return (EPERM);
                    369: #else
                    370:                ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
1.24      thorpej   371:                ip->i_e2fs_flags |=
                    372:                    (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
                    373:                    (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
1.1       bouyer    374: #endif
                    375:                ip->i_flag |= IN_CHANGE;
                    376:                if (vap->va_flags & (IMMUTABLE | APPEND))
                    377:                        return (0);
                    378:        }
                    379:        if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE))
                    380:                return (EPERM);
                    381:        /*
                    382:         * Go through the fields and update iff not VNOVAL.
                    383:         */
                    384:        if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
1.8       fvdl      385:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    386:                        return (EROFS);
1.67      ad        387:                error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
1.1       bouyer    388:                if (error)
                    389:                        return (error);
                    390:        }
                    391:        if (vap->va_size != VNOVAL) {
1.8       fvdl      392:                /*
                    393:                 * Disallow write attempts on read-only file systems;
                    394:                 * unless the file is a socket, fifo, or a block or
                    395:                 * character device resident on the file system.
                    396:                 */
                    397:                switch (vp->v_type) {
                    398:                case VDIR:
1.1       bouyer    399:                        return (EISDIR);
1.8       fvdl      400:                case VLNK:
                    401:                case VREG:
                    402:                        if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    403:                                return (EROFS);
                    404:                default:
                    405:                        break;
                    406:                }
1.64      christos  407:                error = ext2fs_truncate(vp, vap->va_size, 0, cred, l->l_proc);
1.1       bouyer    408:                if (error)
                    409:                        return (error);
                    410:        }
                    411:        ip = VTOI(vp);
                    412:        if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
1.8       fvdl      413:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    414:                        return (EROFS);
1.65      elad      415:                if (kauth_cred_geteuid(cred) != ip->i_e2fs_uid &&
                    416:                        (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
1.72      elad      417:                        NULL)) &&
1.59      perry     418:                        ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
1.64      christos  419:                        (error = VOP_ACCESS(vp, VWRITE, cred, l))))
1.1       bouyer    420:                        return (error);
                    421:                if (vap->va_atime.tv_sec != VNOVAL)
                    422:                        if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
                    423:                                ip->i_flag |= IN_ACCESS;
                    424:                if (vap->va_mtime.tv_sec != VNOVAL)
                    425:                        ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.63      yamt      426:                error = ext2fs_update(vp, &vap->va_atime, &vap->va_mtime,
1.26      perseant  427:                        UPDATE_WAIT);
1.1       bouyer    428:                if (error)
                    429:                        return (error);
                    430:        }
                    431:        error = 0;
1.8       fvdl      432:        if (vap->va_mode != (mode_t)VNOVAL) {
                    433:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    434:                        return (EROFS);
1.67      ad        435:                error = ext2fs_chmod(vp, (int)vap->va_mode, cred, l);
1.8       fvdl      436:        }
1.42      jdolecek  437:        VN_KNOTE(vp, NOTE_ATTRIB);
1.1       bouyer    438:        return (error);
                    439: }
                    440:
                    441: /*
                    442:  * Change the mode on a file.
                    443:  * Inode must be locked before calling.
                    444:  */
                    445: static int
1.67      ad        446: ext2fs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
1.1       bouyer    447: {
1.25      augustss  448:        struct inode *ip = VTOI(vp);
1.65      elad      449:        int error, ismember = 0;
1.1       bouyer    450:
1.65      elad      451:        if (kauth_cred_geteuid(cred) != ip->i_e2fs_uid &&
1.67      ad        452:            (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
1.72      elad      453:            NULL)))
1.1       bouyer    454:                return (error);
1.72      elad      455:        if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)) {
1.1       bouyer    456:                if (vp->v_type != VDIR && (mode & S_ISTXT))
                    457:                        return (EFTYPE);
1.65      elad      458:                if ((kauth_cred_ismember_gid(cred, ip->i_e2fs_gid, &ismember) != 0 ||
                    459:                    !ismember) && (mode & ISGID))
1.1       bouyer    460:                        return (EPERM);
                    461:        }
                    462:        ip->i_e2fs_mode &= ~ALLPERMS;
                    463:        ip->i_e2fs_mode |= (mode & ALLPERMS);
                    464:        ip->i_flag |= IN_CHANGE;
                    465:        return (0);
                    466: }
                    467:
                    468: /*
                    469:  * Perform chown operation on inode ip;
                    470:  * inode must be locked prior to call.
                    471:  */
                    472: static int
1.65      elad      473: ext2fs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
1.67      ad        474:                struct lwp *l)
1.1       bouyer    475: {
1.25      augustss  476:        struct inode *ip = VTOI(vp);
1.1       bouyer    477:        uid_t ouid;
                    478:        gid_t ogid;
1.65      elad      479:        int error = 0, ismember = 0;
1.1       bouyer    480:
                    481:        if (uid == (uid_t)VNOVAL)
                    482:                uid = ip->i_e2fs_uid;
                    483:        if (gid == (gid_t)VNOVAL)
                    484:                gid = ip->i_e2fs_gid;
                    485:        /*
                    486:         * If we don't own the file, are trying to change the owner
                    487:         * of the file, or are not a member of the target group,
                    488:         * the caller must be superuser or the call fails.
                    489:         */
1.65      elad      490:        if ((kauth_cred_geteuid(cred) != ip->i_e2fs_uid || uid != ip->i_e2fs_uid ||
1.67      ad        491:            (gid != ip->i_e2fs_gid &&
                    492:            !(kauth_cred_getegid(cred) == gid ||
                    493:            (kauth_cred_ismember_gid(cred, gid, &ismember) == 0 && ismember)))) &&
1.72      elad      494:            (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)))
1.1       bouyer    495:                return (error);
                    496:        ogid = ip->i_e2fs_gid;
                    497:        ouid = ip->i_e2fs_uid;
                    498:
                    499:        ip->i_e2fs_gid = gid;
                    500:        ip->i_e2fs_uid = uid;
                    501:        if (ouid != uid || ogid != gid)
                    502:                ip->i_flag |= IN_CHANGE;
1.72      elad      503:        if (ouid != uid && kauth_authorize_generic(cred,
                    504:            KAUTH_GENERIC_ISSUSER, NULL) != 0)
1.1       bouyer    505:                ip->i_e2fs_mode &= ~ISUID;
1.72      elad      506:        if (ogid != gid && kauth_authorize_generic(cred,
                    507:            KAUTH_GENERIC_ISSUSER, NULL) != 0)
1.1       bouyer    508:                ip->i_e2fs_mode &= ~ISGID;
                    509:        return (0);
                    510: }
                    511:
                    512: int
1.61      xtraeme   513: ext2fs_remove(void *v)
1.1       bouyer    514: {
                    515:        struct vop_remove_args /* {
                    516:                struct vnode *a_dvp;
                    517:                struct vnode *a_vp;
                    518:                struct componentname *a_cnp;
                    519:        } */ *ap = v;
1.8       fvdl      520:        struct inode *ip;
                    521:        struct vnode *vp = ap->a_vp;
                    522:        struct vnode *dvp = ap->a_dvp;
1.1       bouyer    523:        int error;
                    524:
                    525:        ip = VTOI(vp);
1.2       fvdl      526:        if (vp->v_type == VDIR ||
                    527:                (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
1.1       bouyer    528:                (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) {
                    529:                error = EPERM;
1.43      jdolecek  530:        } else {
                    531:                error = ext2fs_dirremove(dvp, ap->a_cnp);
                    532:                if (error == 0) {
                    533:                        ip->i_e2fs_nlink--;
                    534:                        ip->i_flag |= IN_CHANGE;
                    535:                }
1.1       bouyer    536:        }
1.43      jdolecek  537:
1.42      jdolecek  538:        VN_KNOTE(vp, NOTE_DELETE);
                    539:        VN_KNOTE(dvp, NOTE_WRITE);
1.1       bouyer    540:        if (dvp == vp)
                    541:                vrele(vp);
                    542:        else
                    543:                vput(vp);
                    544:        vput(dvp);
                    545:        return (error);
                    546: }
                    547:
                    548: /*
                    549:  * link vnode call
                    550:  */
                    551: int
1.61      xtraeme   552: ext2fs_link(void *v)
1.1       bouyer    553: {
                    554:        struct vop_link_args /* {
                    555:                struct vnode *a_dvp;
                    556:                struct vnode *a_vp;
                    557:                struct componentname *a_cnp;
                    558:        } */ *ap = v;
1.8       fvdl      559:        struct vnode *dvp = ap->a_dvp;
                    560:        struct vnode *vp = ap->a_vp;
                    561:        struct componentname *cnp = ap->a_cnp;
                    562:        struct inode *ip;
1.1       bouyer    563:        int error;
                    564:
                    565: #ifdef DIAGNOSTIC
                    566:        if ((cnp->cn_flags & HASBUF) == 0)
                    567:                panic("ext2fs_link: no name");
                    568: #endif
                    569:        if (vp->v_type == VDIR) {
                    570:                VOP_ABORTOP(dvp, cnp);
                    571:                error = EISDIR;
                    572:                goto out2;
                    573:        }
                    574:        if (dvp->v_mount != vp->v_mount) {
                    575:                VOP_ABORTOP(dvp, cnp);
                    576:                error = EXDEV;
                    577:                goto out2;
                    578:        }
1.8       fvdl      579:        if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) {
1.1       bouyer    580:                VOP_ABORTOP(dvp, cnp);
                    581:                goto out2;
                    582:        }
                    583:        ip = VTOI(vp);
                    584:        if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
                    585:                VOP_ABORTOP(dvp, cnp);
                    586:                error = EMLINK;
                    587:                goto out1;
                    588:        }
                    589:        if (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) {
                    590:                VOP_ABORTOP(dvp, cnp);
                    591:                error = EPERM;
                    592:                goto out1;
                    593:        }
                    594:        ip->i_e2fs_nlink++;
                    595:        ip->i_flag |= IN_CHANGE;
1.63      yamt      596:        error = ext2fs_update(vp, NULL, NULL, UPDATE_WAIT);
1.1       bouyer    597:        if (!error)
                    598:                error = ext2fs_direnter(ip, dvp, cnp);
                    599:        if (error) {
                    600:                ip->i_e2fs_nlink--;
                    601:                ip->i_flag |= IN_CHANGE;
                    602:        }
1.29      thorpej   603:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       bouyer    604: out1:
                    605:        if (dvp != vp)
1.8       fvdl      606:                VOP_UNLOCK(vp, 0);
1.1       bouyer    607: out2:
1.42      jdolecek  608:        VN_KNOTE(vp, NOTE_LINK);
                    609:        VN_KNOTE(dvp, NOTE_WRITE);
1.1       bouyer    610:        vput(dvp);
                    611:        return (error);
                    612: }
                    613:
                    614: /*
                    615:  * Rename system call.
                    616:  *     rename("foo", "bar");
                    617:  * is essentially
                    618:  *     unlink("bar");
                    619:  *     link("foo", "bar");
                    620:  *     unlink("foo");
                    621:  * but ``atomically''.  Can't do full commit without saving state in the
                    622:  * inode on disk which isn't feasible at this time.  Best we can do is
                    623:  * always guarantee the target exists.
                    624:  *
                    625:  * Basic algorithm is:
                    626:  *
                    627:  * 1) Bump link count on source while we're linking it to the
                    628:  *    target.  This also ensure the inode won't be deleted out
                    629:  *    from underneath us while we work (it may be truncated by
                    630:  *    a concurrent `trunc' or `open' for creation).
                    631:  * 2) Link source to destination.  If destination already exists,
                    632:  *    delete it first.
                    633:  * 3) Unlink source reference to inode if still around. If a
                    634:  *    directory was moved and the parent of the destination
                    635:  *    is different from the source, patch the ".." entry in the
                    636:  *    directory.
                    637:  */
                    638: int
1.61      xtraeme   639: ext2fs_rename(void *v)
1.1       bouyer    640: {
                    641:        struct vop_rename_args  /* {
                    642:                struct vnode *a_fdvp;
                    643:                struct vnode *a_fvp;
                    644:                struct componentname *a_fcnp;
                    645:                struct vnode *a_tdvp;
                    646:                struct vnode *a_tvp;
                    647:                struct componentname *a_tcnp;
                    648:        } */ *ap = v;
                    649:        struct vnode *tvp = ap->a_tvp;
1.25      augustss  650:        struct vnode *tdvp = ap->a_tdvp;
1.1       bouyer    651:        struct vnode *fvp = ap->a_fvp;
1.8       fvdl      652:        struct vnode *fdvp = ap->a_fdvp;
                    653:        struct componentname *tcnp = ap->a_tcnp;
                    654:        struct componentname *fcnp = ap->a_fcnp;
                    655:        struct inode *ip, *xp, *dp;
1.1       bouyer    656:        struct ext2fs_dirtemplate dirbuf;
                    657:        int doingdirectory = 0, oldparent = 0, newparent = 0;
                    658:        int error = 0;
                    659:        u_char namlen;
                    660:
                    661: #ifdef DIAGNOSTIC
                    662:        if ((tcnp->cn_flags & HASBUF) == 0 ||
                    663:            (fcnp->cn_flags & HASBUF) == 0)
                    664:                panic("ext2fs_rename: no name");
                    665: #endif
                    666:        /*
                    667:         * Check for cross-device rename.
                    668:         */
                    669:        if ((fvp->v_mount != tdvp->v_mount) ||
                    670:            (tvp && (fvp->v_mount != tvp->v_mount))) {
                    671:                error = EXDEV;
                    672: abortit:
                    673:                VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
                    674:                if (tdvp == tvp)
                    675:                        vrele(tdvp);
                    676:                else
                    677:                        vput(tdvp);
                    678:                if (tvp)
                    679:                        vput(tvp);
                    680:                VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
                    681:                vrele(fdvp);
                    682:                vrele(fvp);
                    683:                return (error);
                    684:        }
                    685:
                    686:        /*
                    687:         * Check if just deleting a link name.
                    688:         */
                    689:        if (tvp && ((VTOI(tvp)->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
                    690:            (VTOI(tdvp)->i_e2fs_flags & EXT2_APPEND))) {
                    691:                error = EPERM;
                    692:                goto abortit;
                    693:        }
                    694:        if (fvp == tvp) {
                    695:                if (fvp->v_type == VDIR) {
                    696:                        error = EINVAL;
                    697:                        goto abortit;
                    698:                }
                    699:
                    700:                /* Release destination completely. */
                    701:                VOP_ABORTOP(tdvp, tcnp);
                    702:                vput(tdvp);
                    703:                vput(tvp);
                    704:
                    705:                /* Delete source. */
                    706:                vrele(fvp);
1.70      chs       707:                fcnp->cn_flags &= ~(MODMASK | SAVESTART);
1.1       bouyer    708:                fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
                    709:                fcnp->cn_nameiop = DELETE;
1.70      chs       710:                vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
                    711:                if ((error = relookup(fdvp, &fvp, fcnp))) {
                    712:                        vput(fdvp);
                    713:                        return (error);
                    714:                }
1.1       bouyer    715:                return (VOP_REMOVE(fdvp, fvp, fcnp));
                    716:        }
1.8       fvdl      717:        if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1.1       bouyer    718:                goto abortit;
                    719:        dp = VTOI(fdvp);
                    720:        ip = VTOI(fvp);
1.17      mrg       721:        if ((nlink_t) ip->i_e2fs_nlink >= LINK_MAX) {
                    722:                VOP_UNLOCK(fvp, 0);
                    723:                error = EMLINK;
                    724:                goto abortit;
                    725:        }
1.1       bouyer    726:        if ((ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
                    727:                (dp->i_e2fs_flags & EXT2_APPEND)) {
1.8       fvdl      728:                VOP_UNLOCK(fvp, 0);
1.1       bouyer    729:                error = EPERM;
                    730:                goto abortit;
                    731:        }
                    732:        if ((ip->i_e2fs_mode & IFMT) == IFDIR) {
1.64      christos  733:                error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_lwp);
1.16      bouyer    734:                if (!error && tvp)
                    735:                        error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred,
1.64      christos  736:                            tcnp->cn_lwp);
1.16      bouyer    737:                if (error) {
                    738:                        VOP_UNLOCK(fvp, 0);
                    739:                        error = EACCES;
                    740:                        goto abortit;
                    741:                }
1.1       bouyer    742:                /*
                    743:                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                    744:                 */
                    745:                if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
1.3       bouyer    746:                    dp == ip ||
1.70      chs       747:                    (fcnp->cn_flags & ISDOTDOT) ||
1.16      bouyer    748:                    (tcnp->cn_flags & ISDOTDOT) ||
1.1       bouyer    749:                    (ip->i_flag & IN_RENAME)) {
1.8       fvdl      750:                        VOP_UNLOCK(fvp, 0);
1.1       bouyer    751:                        error = EINVAL;
                    752:                        goto abortit;
                    753:                }
                    754:                ip->i_flag |= IN_RENAME;
                    755:                oldparent = dp->i_number;
1.70      chs       756:                doingdirectory = 1;
1.1       bouyer    757:        }
1.42      jdolecek  758:        VN_KNOTE(fdvp, NOTE_WRITE);             /* XXXLUKEM/XXX: right place? */
1.1       bouyer    759:
                    760:        /*
                    761:         * When the target exists, both the directory
                    762:         * and target vnodes are returned locked.
                    763:         */
                    764:        dp = VTOI(tdvp);
                    765:        xp = NULL;
                    766:        if (tvp)
                    767:                xp = VTOI(tvp);
                    768:
                    769:        /*
                    770:         * 1) Bump link count while we're moving stuff
                    771:         *    around.  If we crash somewhere before
                    772:         *    completing our work, the link count
                    773:         *    may be wrong, but correctable.
                    774:         */
                    775:        ip->i_e2fs_nlink++;
                    776:        ip->i_flag |= IN_CHANGE;
1.63      yamt      777:        if ((error = ext2fs_update(fvp, NULL, NULL, UPDATE_WAIT)) != 0) {
1.8       fvdl      778:                VOP_UNLOCK(fvp, 0);
1.1       bouyer    779:                goto bad;
                    780:        }
                    781:
                    782:        /*
                    783:         * If ".." must be changed (ie the directory gets a new
                    784:         * parent) then the source directory must not be in the
1.36      wiz       785:         * directory hierarchy above the target, as this would
1.1       bouyer    786:         * orphan everything below the source directory. Also
                    787:         * the user must have write permission in the source so
1.59      perry     788:         * as to be able to change "..". We must repeat the call
1.1       bouyer    789:         * to namei, as the parent directory is unlocked by the
                    790:         * call to checkpath().
                    791:         */
1.64      christos  792:        error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_lwp);
1.8       fvdl      793:        VOP_UNLOCK(fvp, 0);
1.1       bouyer    794:        if (oldparent != dp->i_number)
                    795:                newparent = dp->i_number;
                    796:        if (doingdirectory && newparent) {
                    797:                if (error)      /* write access check above */
                    798:                        goto bad;
                    799:                if (xp != NULL)
                    800:                        vput(tvp);
1.70      chs       801:                vref(tdvp);     /* compensate for the ref checkpath loses */
1.47      thorpej   802:                error = ext2fs_checkpath(ip, dp, tcnp->cn_cred);
1.70      chs       803:                if (error != 0) {
                    804:                        vrele(tdvp);
1.1       bouyer    805:                        goto out;
1.70      chs       806:                }
                    807:                tcnp->cn_flags &= ~SAVESTART;
                    808:                vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
                    809:                if ((error = relookup(tdvp, &tvp, tcnp)) != 0) {
                    810:                        vput(tdvp);
1.1       bouyer    811:                        goto out;
1.70      chs       812:                }
1.1       bouyer    813:                dp = VTOI(tdvp);
                    814:                xp = NULL;
                    815:                if (tvp)
                    816:                        xp = VTOI(tvp);
                    817:        }
                    818:        /*
                    819:         * 2) If target doesn't exist, link the target
1.59      perry     820:         *    to the source and unlink the source.
1.1       bouyer    821:         *    Otherwise, rewrite the target directory
                    822:         *    entry to reference the source inode and
                    823:         *    expunge the original entry's existence.
                    824:         */
                    825:        if (xp == NULL) {
                    826:                if (dp->i_dev != ip->i_dev)
                    827:                        panic("rename: EXDEV");
                    828:                /*
                    829:                 * Account for ".." in new directory.
                    830:                 * When source and destination have the same
                    831:                 * parent we don't fool with the link count.
                    832:                 */
                    833:                if (doingdirectory && newparent) {
                    834:                        if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
                    835:                                error = EMLINK;
                    836:                                goto bad;
                    837:                        }
                    838:                        dp->i_e2fs_nlink++;
                    839:                        dp->i_flag |= IN_CHANGE;
1.63      yamt      840:                        if ((error = ext2fs_update(tdvp, NULL, NULL,
                    841:                            UPDATE_WAIT)) != 0)
1.1       bouyer    842:                                goto bad;
                    843:                }
                    844:                error = ext2fs_direnter(ip, tdvp, tcnp);
                    845:                if (error != 0) {
                    846:                        if (doingdirectory && newparent) {
                    847:                                dp->i_e2fs_nlink--;
                    848:                                dp->i_flag |= IN_CHANGE;
1.63      yamt      849:                                (void)ext2fs_update(tdvp, NULL, NULL,
                    850:                                    UPDATE_WAIT);
1.1       bouyer    851:                        }
                    852:                        goto bad;
                    853:                }
1.42      jdolecek  854:                VN_KNOTE(tdvp, NOTE_WRITE);
1.1       bouyer    855:                vput(tdvp);
                    856:        } else {
                    857:                if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
                    858:                        panic("rename: EXDEV");
                    859:                /*
                    860:                 * Short circuit rename(foo, foo).
                    861:                 */
                    862:                if (xp->i_number == ip->i_number)
                    863:                        panic("rename: same file");
                    864:                /*
                    865:                 * If the parent directory is "sticky", then the user must
                    866:                 * own the parent directory, or the destination of the rename,
                    867:                 * otherwise the destination may not be changed (except by
                    868:                 * root). This implements append-only directories.
                    869:                 */
1.72      elad      870:                if ((dp->i_e2fs_mode & S_ISTXT) &&
                    871:                    kauth_authorize_generic(tcnp->cn_cred,
                    872:                     KAUTH_GENERIC_ISSUSER, NULL) != 0 &&
1.65      elad      873:                    kauth_cred_geteuid(tcnp->cn_cred) != dp->i_e2fs_uid &&
                    874:                    xp->i_e2fs_uid != kauth_cred_geteuid(tcnp->cn_cred)) {
1.1       bouyer    875:                        error = EPERM;
                    876:                        goto bad;
                    877:                }
                    878:                /*
                    879:                 * Target must be empty if a directory and have no links
                    880:                 * to it. Also, ensure source and target are compatible
                    881:                 * (both directories, or both not directories).
                    882:                 */
                    883:                if ((xp->i_e2fs_mode & IFMT) == IFDIR) {
                    884:                        if (!ext2fs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
                    885:                                xp->i_e2fs_nlink > 2) {
                    886:                                error = ENOTEMPTY;
                    887:                                goto bad;
                    888:                        }
                    889:                        if (!doingdirectory) {
                    890:                                error = ENOTDIR;
                    891:                                goto bad;
                    892:                        }
                    893:                        cache_purge(tdvp);
                    894:                } else if (doingdirectory) {
                    895:                        error = EISDIR;
                    896:                        goto bad;
                    897:                }
                    898:                error = ext2fs_dirrewrite(dp, ip, tcnp);
                    899:                if (error != 0)
                    900:                        goto bad;
                    901:                /*
                    902:                 * If the target directory is in the same
                    903:                 * directory as the source directory,
                    904:                 * decrement the link count on the parent
                    905:                 * of the target directory.
                    906:                 */
                    907:                 if (doingdirectory && !newparent) {
                    908:                        dp->i_e2fs_nlink--;
                    909:                        dp->i_flag |= IN_CHANGE;
                    910:                }
                    911:                /*
                    912:                 * Adjust the link count of the target to
                    913:                 * reflect the dirrewrite above.  If this is
                    914:                 * a directory it is empty and there are
                    915:                 * no links to it, so we can squash the inode and
                    916:                 * any space associated with it.  We disallowed
                    917:                 * renaming over top of a directory with links to
                    918:                 * it above, as the remaining link would point to
                    919:                 * a directory without "." or ".." entries.
                    920:                 */
                    921:                xp->i_e2fs_nlink--;
                    922:                if (doingdirectory) {
                    923:                        if (--xp->i_e2fs_nlink != 0)
                    924:                                panic("rename: linked directory");
1.63      yamt      925:                        error = ext2fs_truncate(tvp, (off_t)0, IO_SYNC,
1.64      christos  926:                            tcnp->cn_cred, tcnp->cn_lwp->l_proc);
1.1       bouyer    927:                }
                    928:                xp->i_flag |= IN_CHANGE;
1.70      chs       929:                VN_KNOTE(tdvp, NOTE_WRITE);
                    930:                vput(tdvp);
1.42      jdolecek  931:                VN_KNOTE(tvp, NOTE_DELETE);
1.1       bouyer    932:                vput(tvp);
                    933:                xp = NULL;
                    934:        }
                    935:
                    936:        /*
                    937:         * 3) Unlink the source.
                    938:         */
1.70      chs       939:        fcnp->cn_flags &= ~(MODMASK | SAVESTART);
1.1       bouyer    940:        fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1.70      chs       941:        vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
                    942:        if ((error = relookup(fdvp, &fvp, fcnp))) {
                    943:                vput(fdvp);
                    944:                vrele(ap->a_fvp);
                    945:                return (error);
                    946:        }
1.1       bouyer    947:        if (fvp != NULL) {
                    948:                xp = VTOI(fvp);
                    949:                dp = VTOI(fdvp);
                    950:        } else {
                    951:                /*
                    952:                 * From name has disappeared.
                    953:                 */
                    954:                if (doingdirectory)
                    955:                        panic("ext2fs_rename: lost dir entry");
                    956:                vrele(ap->a_fvp);
                    957:                return (0);
                    958:        }
                    959:        /*
                    960:         * Ensure that the directory entry still exists and has not
                    961:         * changed while the new name has been entered. If the source is
                    962:         * a file then the entry may have been unlinked or renamed. In
                    963:         * either case there is no further work to be done. If the source
                    964:         * is a directory then it cannot have been rmdir'ed; its link
                    965:         * count of three would cause a rmdir to fail with ENOTEMPTY.
                    966:         * The IRENAME flag ensures that it cannot be moved by another
                    967:         * rename.
                    968:         */
                    969:        if (xp != ip) {
                    970:                if (doingdirectory)
                    971:                        panic("ext2fs_rename: lost dir entry");
                    972:        } else {
                    973:                /*
                    974:                 * If the source is a directory with a
                    975:                 * new parent, the link count of the old
                    976:                 * parent directory must be decremented
                    977:                 * and ".." set to point to the new parent.
                    978:                 */
                    979:                if (doingdirectory && newparent) {
1.69      christos  980:                        KASSERT(dp != NULL);
1.1       bouyer    981:                        dp->i_e2fs_nlink--;
                    982:                        dp->i_flag |= IN_CHANGE;
1.74      christos  983:                        error = vn_rdwr(UIO_READ, fvp, (void *)&dirbuf,
1.1       bouyer    984:                                sizeof (struct ext2fs_dirtemplate), (off_t)0,
1.59      perry     985:                                UIO_SYSSPACE, IO_NODELOCKED,
1.56      skrll     986:                                tcnp->cn_cred, (size_t *)0, NULL);
1.1       bouyer    987:                        if (error == 0) {
1.22      bouyer    988:                                        namlen = dirbuf.dotdot_namlen;
1.1       bouyer    989:                                if (namlen != 2 ||
                    990:                                    dirbuf.dotdot_name[0] != '.' ||
                    991:                                    dirbuf.dotdot_name[1] != '.') {
                    992:                                        ufs_dirbad(xp, (doff_t)12,
                    993:                                            "ext2fs_rename: mangled dir");
                    994:                                } else {
1.4       bouyer    995:                                        dirbuf.dotdot_ino = h2fs32(newparent);
1.1       bouyer    996:                                        (void) vn_rdwr(UIO_WRITE, fvp,
1.74      christos  997:                                            (void *)&dirbuf,
1.1       bouyer    998:                                            sizeof (struct dirtemplate),
                    999:                                            (off_t)0, UIO_SYSSPACE,
                   1000:                                            IO_NODELOCKED|IO_SYNC,
1.12      mjacob   1001:                                            tcnp->cn_cred, (size_t *)0,
1.56      skrll    1002:                                            NULL);
1.1       bouyer   1003:                                        cache_purge(fdvp);
                   1004:                                }
                   1005:                        }
                   1006:                }
                   1007:                error = ext2fs_dirremove(fdvp, fcnp);
                   1008:                if (!error) {
                   1009:                        xp->i_e2fs_nlink--;
                   1010:                        xp->i_flag |= IN_CHANGE;
                   1011:                }
                   1012:                xp->i_flag &= ~IN_RENAME;
                   1013:        }
1.42      jdolecek 1014:        VN_KNOTE(fvp, NOTE_RENAME);
1.70      chs      1015:        if (dp)
                   1016:                vput(fdvp);
1.1       bouyer   1017:        if (xp)
                   1018:                vput(fvp);
1.70      chs      1019:        vrele(ap->a_fvp);
1.1       bouyer   1020:        return (error);
                   1021:
                   1022: bad:
                   1023:        if (xp)
                   1024:                vput(ITOV(xp));
                   1025:        vput(ITOV(dp));
                   1026: out:
                   1027:        if (doingdirectory)
                   1028:                ip->i_flag &= ~IN_RENAME;
1.8       fvdl     1029:        if (vn_lock(fvp, LK_EXCLUSIVE) == 0) {
1.1       bouyer   1030:                ip->i_e2fs_nlink--;
                   1031:                ip->i_flag |= IN_CHANGE;
                   1032:                vput(fvp);
                   1033:        } else
                   1034:                vrele(fvp);
1.70      chs      1035:        vrele(fdvp);
1.1       bouyer   1036:        return (error);
                   1037: }
                   1038:
                   1039: /*
                   1040:  * Mkdir system call
                   1041:  */
                   1042: int
1.61      xtraeme  1043: ext2fs_mkdir(void *v)
1.1       bouyer   1044: {
                   1045:        struct vop_mkdir_args /* {
                   1046:                struct vnode *a_dvp;
                   1047:                struct vnode **a_vpp;
                   1048:                struct componentname *a_cnp;
                   1049:                struct vattr *a_vap;
                   1050:        } */ *ap = v;
1.55      mycroft  1051:        struct vnode            *dvp = ap->a_dvp;
                   1052:        struct vattr            *vap = ap->a_vap;
                   1053:        struct componentname    *cnp = ap->a_cnp;
                   1054:        struct inode            *ip, *dp = VTOI(dvp);
                   1055:        struct vnode            *tvp;
1.4       bouyer   1056:        struct ext2fs_dirtemplate dirtemplate;
1.55      mycroft  1057:        int                     error, dmode;
1.1       bouyer   1058:
                   1059: #ifdef DIAGNOSTIC
                   1060:        if ((cnp->cn_flags & HASBUF) == 0)
                   1061:                panic("ext2fs_mkdir: no name");
                   1062: #endif
                   1063:        if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
                   1064:                error = EMLINK;
                   1065:                goto out;
                   1066:        }
                   1067:        dmode = vap->va_mode & ACCESSPERMS;
                   1068:        dmode |= IFDIR;
                   1069:        /*
                   1070:         * Must simulate part of ext2fs_makeinode here to acquire the inode,
                   1071:         * but not have it entered in the parent directory. The entry is
                   1072:         * made later after writing "." and ".." entries.
                   1073:         */
1.63      yamt     1074:        if ((error = ext2fs_valloc(dvp, dmode, cnp->cn_cred, &tvp)) != 0)
1.1       bouyer   1075:                goto out;
                   1076:        ip = VTOI(tvp);
1.65      elad     1077:        ip->i_e2fs_uid = kauth_cred_geteuid(cnp->cn_cred);
1.1       bouyer   1078:        ip->i_e2fs_gid = dp->i_e2fs_gid;
                   1079:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
                   1080:        ip->i_e2fs_mode = dmode;
                   1081:        tvp->v_type = VDIR;     /* Rest init'd in getnewvnode(). */
                   1082:        ip->i_e2fs_nlink = 2;
                   1083:
                   1084:        /*
                   1085:         * Bump link count in parent directory
                   1086:         * to reflect work done below.  Should
                   1087:         * be done before reference is created
                   1088:         * so reparation is possible if we crash.
                   1089:         */
                   1090:        dp->i_e2fs_nlink++;
                   1091:        dp->i_flag |= IN_CHANGE;
1.63      yamt     1092:        if ((error = ext2fs_update(dvp, NULL, NULL, UPDATE_DIROP)) != 0)
1.1       bouyer   1093:                goto bad;
                   1094:
                   1095:        /* Initialize directory with "." and ".." from static template. */
1.13      perry    1096:        memset(&dirtemplate, 0, sizeof(dirtemplate));
1.4       bouyer   1097:        dirtemplate.dot_ino = h2fs32(ip->i_number);
                   1098:        dirtemplate.dot_reclen = h2fs16(12);
1.22      bouyer   1099:        dirtemplate.dot_namlen = 1;
                   1100:        if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
                   1101:            (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
1.23      bouyer   1102:                dirtemplate.dot_type = EXT2_FT_DIR;
1.22      bouyer   1103:        }
1.4       bouyer   1104:        dirtemplate.dot_name[0] = '.';
                   1105:        dirtemplate.dotdot_ino = h2fs32(dp->i_number);
                   1106:     dirtemplate.dotdot_reclen = h2fs16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12);
1.22      bouyer   1107:        dirtemplate.dotdot_namlen = 2;
                   1108:        if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
                   1109:            (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
1.23      bouyer   1110:                dirtemplate.dotdot_type = EXT2_FT_DIR;
1.22      bouyer   1111:        }
1.4       bouyer   1112:        dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
1.74      christos 1113:        error = vn_rdwr(UIO_WRITE, tvp, (void *)&dirtemplate,
1.1       bouyer   1114:            sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
1.56      skrll    1115:            IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (size_t *)0, NULL);
1.1       bouyer   1116:        if (error) {
                   1117:                dp->i_e2fs_nlink--;
                   1118:                dp->i_flag |= IN_CHANGE;
                   1119:                goto bad;
                   1120:        }
1.55      mycroft  1121:        if (VTOI(dvp)->i_e2fs->e2fs_bsize > dvp->v_mount->mnt_stat.f_bsize)
1.1       bouyer   1122:                panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */
                   1123:        else {
1.58      ws       1124:                error = ext2fs_setsize(ip, VTOI(dvp)->i_e2fs->e2fs_bsize);
                   1125:                if (error) {
                   1126:                        dp->i_e2fs_nlink--;
                   1127:                        dp->i_flag |= IN_CHANGE;
                   1128:                        goto bad;
                   1129:                }
1.1       bouyer   1130:                ip->i_flag |= IN_CHANGE;
1.60      kml      1131:                uvm_vnp_setsize(tvp, ext2fs_size(ip));
1.1       bouyer   1132:        }
                   1133:
                   1134:        /* Directory set up, now install it's entry in the parent directory. */
                   1135:        error = ext2fs_direnter(ip, dvp, cnp);
                   1136:        if (error != 0) {
                   1137:                dp->i_e2fs_nlink--;
                   1138:                dp->i_flag |= IN_CHANGE;
                   1139:        }
                   1140: bad:
                   1141:        /*
1.63      yamt     1142:         * No need to do an explicit ext2fs_truncate here, vrele will do this
1.1       bouyer   1143:         * for us because we set the link count to 0.
                   1144:         */
                   1145:        if (error) {
                   1146:                ip->i_e2fs_nlink = 0;
                   1147:                ip->i_flag |= IN_CHANGE;
                   1148:                vput(tvp);
1.42      jdolecek 1149:        } else {
                   1150:                VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1.1       bouyer   1151:                *ap->a_vpp = tvp;
1.42      jdolecek 1152:        }
1.1       bouyer   1153: out:
1.29      thorpej  1154:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       bouyer   1155:        vput(dvp);
                   1156:        return (error);
                   1157: }
                   1158:
                   1159: /*
                   1160:  * Rmdir system call.
                   1161:  */
                   1162: int
1.61      xtraeme  1163: ext2fs_rmdir(void *v)
1.1       bouyer   1164: {
                   1165:        struct vop_rmdir_args /* {
                   1166:                struct vnode *a_dvp;
                   1167:                struct vnode *a_vp;
                   1168:                struct componentname *a_cnp;
                   1169:        } */ *ap = v;
1.25      augustss 1170:        struct vnode *vp = ap->a_vp;
                   1171:        struct vnode *dvp = ap->a_dvp;
                   1172:        struct componentname *cnp = ap->a_cnp;
                   1173:        struct inode *ip, *dp;
1.1       bouyer   1174:        int error;
                   1175:
                   1176:        ip = VTOI(vp);
                   1177:        dp = VTOI(dvp);
                   1178:        /*
                   1179:         * No rmdir "." please.
                   1180:         */
                   1181:        if (dp == ip) {
                   1182:                vrele(dvp);
                   1183:                vput(vp);
                   1184:                return (EINVAL);
                   1185:        }
                   1186:        /*
                   1187:         * Verify the directory is empty (and valid).
                   1188:         * (Rmdir ".." won't be valid since
                   1189:         *  ".." will contain a reference to
                   1190:         *  the current directory and thus be
                   1191:         *  non-empty.)
                   1192:         */
                   1193:        error = 0;
                   1194:        if (ip->i_e2fs_nlink != 2 ||
                   1195:            !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
                   1196:                error = ENOTEMPTY;
                   1197:                goto out;
                   1198:        }
                   1199:        if ((dp->i_e2fs_flags & EXT2_APPEND) ||
                   1200:                                 (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) {
                   1201:                error = EPERM;
                   1202:                goto out;
                   1203:        }
                   1204:        /*
                   1205:         * Delete reference to directory before purging
                   1206:         * inode.  If we crash in between, the directory
                   1207:         * will be reattached to lost+found,
                   1208:         */
                   1209:        error = ext2fs_dirremove(dvp, cnp);
                   1210:        if (error != 0)
                   1211:                goto out;
                   1212:        dp->i_e2fs_nlink--;
                   1213:        dp->i_flag |= IN_CHANGE;
1.42      jdolecek 1214:        VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1.1       bouyer   1215:        cache_purge(dvp);
                   1216:        vput(dvp);
                   1217:        dvp = NULL;
                   1218:        /*
                   1219:         * Truncate inode.  The only stuff left
                   1220:         * in the directory is "." and "..".  The
                   1221:         * "." reference is inconsequential since
                   1222:         * we're quashing it.  The ".." reference
                   1223:         * has already been adjusted above.  We've
                   1224:         * removed the "." reference and the reference
                   1225:         * in the parent directory, but there may be
                   1226:         * other hard links so decrement by 2 and
                   1227:         * worry about them later.
                   1228:         */
                   1229:        ip->i_e2fs_nlink -= 2;
1.63      yamt     1230:        error = ext2fs_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred,
1.64      christos 1231:            cnp->cn_lwp->l_proc);
1.1       bouyer   1232:        cache_purge(ITOV(ip));
                   1233: out:
1.42      jdolecek 1234:        VN_KNOTE(vp, NOTE_DELETE);
1.1       bouyer   1235:        if (dvp)
                   1236:                vput(dvp);
                   1237:        vput(vp);
                   1238:        return (error);
                   1239: }
                   1240:
                   1241: /*
                   1242:  * symlink -- make a symbolic link
                   1243:  */
                   1244: int
1.61      xtraeme  1245: ext2fs_symlink(void *v)
1.1       bouyer   1246: {
                   1247:        struct vop_symlink_args /* {
                   1248:                struct vnode *a_dvp;
                   1249:                struct vnode **a_vpp;
                   1250:                struct componentname *a_cnp;
                   1251:                struct vattr *a_vap;
                   1252:                char *a_target;
                   1253:        } */ *ap = v;
1.55      mycroft  1254:        struct vnode    *vp, **vpp;
                   1255:        struct inode    *ip;
                   1256:        int             len, error;
1.1       bouyer   1257:
1.55      mycroft  1258:        vpp = ap->a_vpp;
1.1       bouyer   1259:        error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
                   1260:                              vpp, ap->a_cnp);
                   1261:        if (error)
                   1262:                return (error);
1.42      jdolecek 1263:        VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.1       bouyer   1264:        vp = *vpp;
                   1265:        len = strlen(ap->a_target);
1.55      mycroft  1266:        ip = VTOI(vp);
                   1267:        if (len < ip->i_ump->um_maxsymlinklen) {
1.44      fvdl     1268:                memcpy((char *)ip->i_din.e2fs_din->e2di_shortlink, ap->a_target, len);
1.58      ws       1269:                error = ext2fs_setsize(ip, len);
                   1270:                if (error)
                   1271:                        goto bad;
1.1       bouyer   1272:                ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.60      kml      1273:                uvm_vnp_setsize(vp, len);
1.1       bouyer   1274:        } else
                   1275:                error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1.12      mjacob   1276:                    UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred,
1.56      skrll    1277:                    (size_t *)0, NULL);
1.58      ws       1278: bad:
1.34      assar    1279:        if (error)
                   1280:                vput(vp);
1.1       bouyer   1281:        return (error);
                   1282: }
                   1283:
                   1284: /*
                   1285:  * Return target name of a symbolic link
                   1286:  */
                   1287: int
1.61      xtraeme  1288: ext2fs_readlink(void *v)
1.1       bouyer   1289: {
                   1290:        struct vop_readlink_args /* {
                   1291:                struct vnode *a_vp;
                   1292:                struct uio *a_uio;
1.65      elad     1293:                kauth_cred_t a_cred;
1.1       bouyer   1294:        } */ *ap = v;
1.55      mycroft  1295:        struct vnode    *vp = ap->a_vp;
                   1296:        struct inode    *ip = VTOI(vp);
                   1297:        struct ufsmount *ump = ip->i_ump;
                   1298:        int             isize;
1.1       bouyer   1299:
1.58      ws       1300:        isize = ext2fs_size(ip);
1.55      mycroft  1301:        if (isize < ump->um_maxsymlinklen ||
                   1302:            (ump->um_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) {
1.44      fvdl     1303:                uiomove((char *)ip->i_din.e2fs_din->e2di_shortlink, isize, ap->a_uio);
1.1       bouyer   1304:                return (0);
                   1305:        }
                   1306:        return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
                   1307: }
                   1308:
                   1309: /*
                   1310:  * Advisory record locking support
                   1311:  */
                   1312: int
1.61      xtraeme  1313: ext2fs_advlock(void *v)
1.1       bouyer   1314: {
                   1315:        struct vop_advlock_args /* {
                   1316:                struct vnode *a_vp;
1.74      christos 1317:                void * a_id;
1.1       bouyer   1318:                int  a_op;
                   1319:                struct flock *a_fl;
                   1320:                int  a_flags;
                   1321:        } */ *ap = v;
1.25      augustss 1322:        struct inode *ip = VTOI(ap->a_vp);
1.1       bouyer   1323:
1.58      ws       1324:        return lf_advlock(ap, &ip->i_lockf, ext2fs_size(ip));
1.1       bouyer   1325: }
                   1326:
1.63      yamt     1327: int
                   1328: ext2fs_fsync(void *v)
                   1329: {
                   1330:        struct vop_fsync_args /* {
                   1331:                struct vnode *a_vp;
1.65      elad     1332:                kauth_cred_t a_cred;
1.63      yamt     1333:                int a_flags;
                   1334:                off_t offlo;
                   1335:                off_t offhi;
                   1336:                struct proc *a_p;
                   1337:        } */ *ap = v;
                   1338:        struct vnode *vp = ap->a_vp;
                   1339:        int wait;
                   1340:        int error;
                   1341:
                   1342:        wait = (ap->a_flags & FSYNC_WAIT) != 0;
                   1343:        vflushbuf(vp, wait);
                   1344:        if ((ap->a_flags & FSYNC_DATAONLY) != 0)
                   1345:                error = 0;
                   1346:        else
                   1347:                error = ext2fs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0);
                   1348:
                   1349:        if (error == 0 && ap->a_flags & FSYNC_CACHE) {
                   1350:                int l = 0;
                   1351:                error = VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE,
1.67      ad       1352:                    ap->a_l->l_cred, ap->a_l);
1.63      yamt     1353:        }
                   1354:
                   1355:        return error;
                   1356: }
                   1357:
1.1       bouyer   1358: /*
                   1359:  * Initialize the vnode associated with a new inode, handle aliased
                   1360:  * vnodes.
                   1361:  */
                   1362: int
1.61      xtraeme  1363: ext2fs_vinit(struct mount *mntp, int (**specops)(void *),
                   1364:        int (**fifoops)(void *), struct vnode **vpp)
1.1       bouyer   1365: {
1.66      kardel   1366:        struct timeval tv;
1.1       bouyer   1367:        struct inode *ip;
                   1368:        struct vnode *vp, *nvp;
                   1369:
                   1370:        vp = *vpp;
                   1371:        ip = VTOI(vp);
                   1372:        switch(vp->v_type = IFTOVT(ip->i_e2fs_mode)) {
                   1373:        case VCHR:
                   1374:        case VBLK:
                   1375:                vp->v_op = specops;
1.16      bouyer   1376:                if ((nvp = checkalias(vp,
1.44      fvdl     1377:                    fs2h32(ip->i_din.e2fs_din->e2di_rdev), mntp)) != NULL) {
1.1       bouyer   1378:                        /*
                   1379:                         * Discard unneeded vnode, but save its inode.
                   1380:                         */
                   1381:                        nvp->v_data = vp->v_data;
                   1382:                        vp->v_data = NULL;
1.74.18.1! yamt     1383:                        vp->v_vflag &= ~VV_LOCKSWORK;
1.33      fvdl     1384:                        VOP_UNLOCK(vp, 0);
1.1       bouyer   1385:                        vp->v_op = spec_vnodeop_p;
1.33      fvdl     1386:                        vrele(vp);
1.1       bouyer   1387:                        vgone(vp);
1.20      wrstuden 1388:                        lockmgr(&nvp->v_lock, LK_EXCLUSIVE, &nvp->v_interlock);
1.1       bouyer   1389:                        /*
                   1390:                         * Reinitialize aliased inode.
                   1391:                         */
                   1392:                        vp = nvp;
                   1393:                        ip->i_vnode = vp;
                   1394:                }
                   1395:                break;
                   1396:        case VFIFO:
                   1397:                vp->v_op = fifoops;
                   1398:                break;
                   1399:        case VNON:
                   1400:        case VBAD:
                   1401:        case VSOCK:
                   1402:        case VLNK:
                   1403:        case VDIR:
                   1404:        case VREG:
                   1405:                break;
                   1406:        }
                   1407:        if (ip->i_number == ROOTINO)
1.74.18.1! yamt     1408:                 vp->v_vflag |= VV_ROOT;
1.1       bouyer   1409:        /*
                   1410:         * Initialize modrev times
                   1411:         */
1.66      kardel   1412:        getmicrouptime(&tv);
                   1413:        SETHIGH(ip->i_modrev, tv.tv_sec);
                   1414:        SETLOW(ip->i_modrev, tv.tv_usec * 4294);
1.1       bouyer   1415:        *vpp = vp;
                   1416:        return (0);
                   1417: }
                   1418:
                   1419: /*
                   1420:  * Allocate a new inode.
                   1421:  */
                   1422: int
1.61      xtraeme  1423: ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
                   1424:                struct componentname *cnp)
1.1       bouyer   1425: {
1.25      augustss 1426:        struct inode *ip, *pdir;
1.1       bouyer   1427:        struct vnode *tvp;
1.65      elad     1428:        int error, ismember = 0;
1.1       bouyer   1429:
                   1430:        pdir = VTOI(dvp);
                   1431: #ifdef DIAGNOSTIC
                   1432:        if ((cnp->cn_flags & HASBUF) == 0)
                   1433:                panic("ext2fs_makeinode: no name");
                   1434: #endif
                   1435:        *vpp = NULL;
                   1436:        if ((mode & IFMT) == 0)
                   1437:                mode |= IFREG;
                   1438:
1.63      yamt     1439:        if ((error = ext2fs_valloc(dvp, mode, cnp->cn_cred, &tvp)) != 0) {
1.29      thorpej  1440:                PNBUF_PUT(cnp->cn_pnbuf);
1.1       bouyer   1441:                vput(dvp);
                   1442:                return (error);
                   1443:        }
                   1444:        ip = VTOI(tvp);
                   1445:        ip->i_e2fs_gid = pdir->i_e2fs_gid;
1.65      elad     1446:        ip->i_e2fs_uid = kauth_cred_geteuid(cnp->cn_cred);
1.1       bouyer   1447:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
                   1448:        ip->i_e2fs_mode = mode;
                   1449:        tvp->v_type = IFTOVT(mode);     /* Rest init'd in getnewvnode(). */
                   1450:        ip->i_e2fs_nlink = 1;
1.65      elad     1451:        if ((ip->i_e2fs_mode & ISGID) && (kauth_cred_ismember_gid(cnp->cn_cred,
                   1452:            ip->i_e2fs_gid, &ismember) != 0 || !ismember) &&
                   1453:            kauth_authorize_generic(cnp->cn_cred, KAUTH_GENERIC_ISSUSER, NULL))
1.1       bouyer   1454:                ip->i_e2fs_mode &= ~ISGID;
                   1455:
                   1456:        /*
                   1457:         * Make sure inode goes to disk before directory entry.
                   1458:         */
1.63      yamt     1459:        if ((error = ext2fs_update(tvp, NULL, NULL, UPDATE_WAIT)) != 0)
1.1       bouyer   1460:                goto bad;
                   1461:        error = ext2fs_direnter(ip, dvp, cnp);
                   1462:        if (error != 0)
                   1463:                goto bad;
                   1464:        if ((cnp->cn_flags & SAVESTART) == 0)
1.29      thorpej  1465:                PNBUF_PUT(cnp->cn_pnbuf);
1.1       bouyer   1466:        vput(dvp);
                   1467:        *vpp = tvp;
                   1468:        return (0);
                   1469:
                   1470: bad:
                   1471:        /*
                   1472:         * Write error occurred trying to update the inode
                   1473:         * or the directory so must deallocate the inode.
                   1474:         */
1.50      dsl      1475:        tvp->v_type = VNON;     /* Stop explosion if VBLK */
1.1       bouyer   1476:        ip->i_e2fs_nlink = 0;
                   1477:        ip->i_flag |= IN_CHANGE;
                   1478:        vput(tvp);
1.50      dsl      1479:        PNBUF_PUT(cnp->cn_pnbuf);
                   1480:        vput(dvp);
1.1       bouyer   1481:        return (error);
                   1482: }
                   1483:
                   1484: /*
                   1485:  * Reclaim an inode so that it can be used for other purposes.
                   1486:  */
                   1487: int
1.61      xtraeme  1488: ext2fs_reclaim(void *v)
1.1       bouyer   1489: {
                   1490:        struct vop_reclaim_args /* {
                   1491:                struct vnode *a_vp;
                   1492:        } */ *ap = v;
1.25      augustss 1493:        struct vnode *vp = ap->a_vp;
1.54      mycroft  1494:        struct inode *ip = VTOI(vp);
                   1495:        int error;
1.45      fvdl     1496:
1.64      christos 1497:        if ((error = ufs_reclaim(vp, ap->a_l)) != 0)
1.54      mycroft  1498:                return (error);
1.45      fvdl     1499:        if (ip->i_din.e2fs_din != NULL)
                   1500:                pool_put(&ext2fs_dinode_pool, ip->i_din.e2fs_din);
1.73      ad       1501:        genfs_node_destroy(vp);
1.14      thorpej  1502:        pool_put(&ext2fs_inode_pool, vp->v_data);
1.1       bouyer   1503:        vp->v_data = NULL;
                   1504:        return (0);
                   1505: }
                   1506:
                   1507: /* Global vfs data structures for ext2fs. */
1.61      xtraeme  1508: int (**ext2fs_vnodeop_p)(void *);
1.31      jdolecek 1509: const struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = {
1.1       bouyer   1510:        { &vop_default_desc, vn_default_error },
1.8       fvdl     1511:        { &vop_lookup_desc, ext2fs_lookup },            /* lookup */
                   1512:        { &vop_create_desc, ext2fs_create },            /* create */
1.1       bouyer   1513:        { &vop_mknod_desc, ext2fs_mknod },              /* mknod */
                   1514:        { &vop_open_desc, ext2fs_open },                /* open */
                   1515:        { &vop_close_desc, ufs_close },                 /* close */
1.8       fvdl     1516:        { &vop_access_desc, ext2fs_access },            /* access */
                   1517:        { &vop_getattr_desc, ext2fs_getattr },          /* getattr */
                   1518:        { &vop_setattr_desc, ext2fs_setattr },          /* setattr */
1.1       bouyer   1519:        { &vop_read_desc, ext2fs_read },                /* read */
                   1520:        { &vop_write_desc, ext2fs_write },              /* write */
1.8       fvdl     1521:        { &vop_lease_desc, ufs_lease_check },           /* lease */
1.1       bouyer   1522:        { &vop_ioctl_desc, ufs_ioctl },                 /* ioctl */
1.21      wrstuden 1523:        { &vop_fcntl_desc, ufs_fcntl },                 /* fcntl */
1.1       bouyer   1524:        { &vop_poll_desc, ufs_poll },                   /* poll */
1.42      jdolecek 1525:        { &vop_kqfilter_desc, genfs_kqfilter },         /* kqfilter */
1.8       fvdl     1526:        { &vop_revoke_desc, ufs_revoke },               /* revoke */
1.1       bouyer   1527:        { &vop_mmap_desc, ufs_mmap },                   /* mmap */
                   1528:        { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
                   1529:        { &vop_seek_desc, ufs_seek },                   /* seek */
1.8       fvdl     1530:        { &vop_remove_desc, ext2fs_remove },            /* remove */
1.1       bouyer   1531:        { &vop_link_desc, ext2fs_link },                /* link */
1.8       fvdl     1532:        { &vop_rename_desc, ext2fs_rename },            /* rename */
1.1       bouyer   1533:        { &vop_mkdir_desc, ext2fs_mkdir },              /* mkdir */
                   1534:        { &vop_rmdir_desc, ext2fs_rmdir },              /* rmdir */
1.8       fvdl     1535:        { &vop_symlink_desc, ext2fs_symlink },          /* symlink */
                   1536:        { &vop_readdir_desc, ext2fs_readdir },          /* readdir */
                   1537:        { &vop_readlink_desc, ext2fs_readlink },        /* readlink */
1.1       bouyer   1538:        { &vop_abortop_desc, ufs_abortop },             /* abortop */
1.8       fvdl     1539:        { &vop_inactive_desc, ext2fs_inactive },        /* inactive */
                   1540:        { &vop_reclaim_desc, ext2fs_reclaim },          /* reclaim */
1.1       bouyer   1541:        { &vop_lock_desc, ufs_lock },                   /* lock */
                   1542:        { &vop_unlock_desc, ufs_unlock },               /* unlock */
                   1543:        { &vop_bmap_desc, ext2fs_bmap },                /* bmap */
1.8       fvdl     1544:        { &vop_strategy_desc, ufs_strategy },           /* strategy */
1.1       bouyer   1545:        { &vop_print_desc, ufs_print },                 /* print */
1.8       fvdl     1546:        { &vop_islocked_desc, ufs_islocked },           /* islocked */
                   1547:        { &vop_pathconf_desc, ufs_pathconf },           /* pathconf */
                   1548:        { &vop_advlock_desc, ext2fs_advlock },          /* advlock */
1.1       bouyer   1549:        { &vop_bwrite_desc, vn_bwrite },                /* bwrite */
1.30      chs      1550:        { &vop_getpages_desc, genfs_getpages },         /* getpages */
                   1551:        { &vop_putpages_desc, genfs_putpages },         /* putpages */
                   1552:        { NULL, NULL }
1.1       bouyer   1553: };
1.31      jdolecek 1554: const struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
1.1       bouyer   1555:        { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries };
                   1556:
1.61      xtraeme  1557: int (**ext2fs_specop_p)(void *);
1.31      jdolecek 1558: const struct vnodeopv_entry_desc ext2fs_specop_entries[] = {
1.1       bouyer   1559:        { &vop_default_desc, vn_default_error },
                   1560:        { &vop_lookup_desc, spec_lookup },              /* lookup */
                   1561:        { &vop_create_desc, spec_create },              /* create */
                   1562:        { &vop_mknod_desc, spec_mknod },                /* mknod */
                   1563:        { &vop_open_desc, spec_open },                  /* open */
                   1564:        { &vop_close_desc, ufsspec_close },             /* close */
1.8       fvdl     1565:        { &vop_access_desc, ext2fs_access },            /* access */
                   1566:        { &vop_getattr_desc, ext2fs_getattr },          /* getattr */
                   1567:        { &vop_setattr_desc, ext2fs_setattr },          /* setattr */
1.1       bouyer   1568:        { &vop_read_desc, ufsspec_read },               /* read */
                   1569:        { &vop_write_desc, ufsspec_write },             /* write */
1.8       fvdl     1570:        { &vop_lease_desc, spec_lease_check },          /* lease */
1.1       bouyer   1571:        { &vop_ioctl_desc, spec_ioctl },                /* ioctl */
1.21      wrstuden 1572:        { &vop_fcntl_desc, ufs_fcntl },                 /* fcntl */
1.1       bouyer   1573:        { &vop_poll_desc, spec_poll },                  /* poll */
1.42      jdolecek 1574:        { &vop_kqfilter_desc, spec_kqfilter },          /* kqfilter */
1.8       fvdl     1575:        { &vop_revoke_desc, spec_revoke },              /* revoke */
1.1       bouyer   1576:        { &vop_mmap_desc, spec_mmap },                  /* mmap */
                   1577:        { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
                   1578:        { &vop_seek_desc, spec_seek },                  /* seek */
                   1579:        { &vop_remove_desc, spec_remove },              /* remove */
                   1580:        { &vop_link_desc, spec_link },                  /* link */
                   1581:        { &vop_rename_desc, spec_rename },              /* rename */
                   1582:        { &vop_mkdir_desc, spec_mkdir },                /* mkdir */
                   1583:        { &vop_rmdir_desc, spec_rmdir },                /* rmdir */
1.8       fvdl     1584:        { &vop_symlink_desc, spec_symlink },            /* symlink */
                   1585:        { &vop_readdir_desc, spec_readdir },            /* readdir */
                   1586:        { &vop_readlink_desc, spec_readlink },          /* readlink */
                   1587:        { &vop_abortop_desc, spec_abortop },            /* abortop */
                   1588:        { &vop_inactive_desc, ext2fs_inactive },        /* inactive */
                   1589:        { &vop_reclaim_desc, ext2fs_reclaim },          /* reclaim */
1.1       bouyer   1590:        { &vop_lock_desc, ufs_lock },                   /* lock */
                   1591:        { &vop_unlock_desc, ufs_unlock },               /* unlock */
                   1592:        { &vop_bmap_desc, spec_bmap },                  /* bmap */
1.8       fvdl     1593:        { &vop_strategy_desc, spec_strategy },          /* strategy */
1.1       bouyer   1594:        { &vop_print_desc, ufs_print },                 /* print */
1.8       fvdl     1595:        { &vop_islocked_desc, ufs_islocked },           /* islocked */
                   1596:        { &vop_pathconf_desc, spec_pathconf },          /* pathconf */
                   1597:        { &vop_advlock_desc, spec_advlock },            /* advlock */
1.1       bouyer   1598:        { &vop_bwrite_desc, vn_bwrite },                /* bwrite */
1.35      chs      1599:        { &vop_getpages_desc, spec_getpages },          /* getpages */
                   1600:        { &vop_putpages_desc, spec_putpages },          /* putpages */
1.30      chs      1601:        { NULL, NULL }
1.1       bouyer   1602: };
1.31      jdolecek 1603: const struct vnodeopv_desc ext2fs_specop_opv_desc =
1.1       bouyer   1604:        { &ext2fs_specop_p, ext2fs_specop_entries };
                   1605:
1.61      xtraeme  1606: int (**ext2fs_fifoop_p)(void *);
1.31      jdolecek 1607: const struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = {
1.1       bouyer   1608:        { &vop_default_desc, vn_default_error },
                   1609:        { &vop_lookup_desc, fifo_lookup },              /* lookup */
                   1610:        { &vop_create_desc, fifo_create },              /* create */
                   1611:        { &vop_mknod_desc, fifo_mknod },                /* mknod */
                   1612:        { &vop_open_desc, fifo_open },                  /* open */
                   1613:        { &vop_close_desc, ufsfifo_close },             /* close */
1.8       fvdl     1614:        { &vop_access_desc, ext2fs_access },            /* access */
                   1615:        { &vop_getattr_desc, ext2fs_getattr },          /* getattr */
                   1616:        { &vop_setattr_desc, ext2fs_setattr },          /* setattr */
1.1       bouyer   1617:        { &vop_read_desc, ufsfifo_read },               /* read */
                   1618:        { &vop_write_desc, ufsfifo_write },             /* write */
1.8       fvdl     1619:        { &vop_lease_desc, fifo_lease_check },          /* lease */
1.1       bouyer   1620:        { &vop_ioctl_desc, fifo_ioctl },                /* ioctl */
1.21      wrstuden 1621:        { &vop_fcntl_desc, ufs_fcntl },                 /* fcntl */
1.1       bouyer   1622:        { &vop_poll_desc, fifo_poll },                  /* poll */
1.42      jdolecek 1623:        { &vop_kqfilter_desc, fifo_kqfilter },          /* kqfilter */
1.8       fvdl     1624:        { &vop_revoke_desc, fifo_revoke },              /* revoke */
1.1       bouyer   1625:        { &vop_mmap_desc, fifo_mmap },                  /* mmap */
                   1626:        { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
                   1627:        { &vop_seek_desc, fifo_seek },                  /* seek */
                   1628:        { &vop_remove_desc, fifo_remove },              /* remove */
                   1629:        { &vop_link_desc, fifo_link },                  /* link */
                   1630:        { &vop_rename_desc, fifo_rename },              /* rename */
                   1631:        { &vop_mkdir_desc, fifo_mkdir },                /* mkdir */
                   1632:        { &vop_rmdir_desc, fifo_rmdir },                /* rmdir */
1.8       fvdl     1633:        { &vop_symlink_desc, fifo_symlink },            /* symlink */
                   1634:        { &vop_readdir_desc, fifo_readdir },            /* readdir */
                   1635:        { &vop_readlink_desc, fifo_readlink },          /* readlink */
                   1636:        { &vop_abortop_desc, fifo_abortop },            /* abortop */
                   1637:        { &vop_inactive_desc, ext2fs_inactive },        /* inactive */
                   1638:        { &vop_reclaim_desc, ext2fs_reclaim },          /* reclaim */
1.1       bouyer   1639:        { &vop_lock_desc, ufs_lock },                   /* lock */
                   1640:        { &vop_unlock_desc, ufs_unlock },               /* unlock */
                   1641:        { &vop_bmap_desc, fifo_bmap },                  /* bmap */
1.8       fvdl     1642:        { &vop_strategy_desc, fifo_strategy },          /* strategy */
1.1       bouyer   1643:        { &vop_print_desc, ufs_print },                 /* print */
1.8       fvdl     1644:        { &vop_islocked_desc, ufs_islocked },           /* islocked */
                   1645:        { &vop_pathconf_desc, fifo_pathconf },          /* pathconf */
                   1646:        { &vop_advlock_desc, fifo_advlock },            /* advlock */
1.1       bouyer   1647:        { &vop_bwrite_desc, vn_bwrite },                /* bwrite */
1.38      sommerfe 1648:        { &vop_putpages_desc, fifo_putpages },          /* putpages */
1.30      chs      1649:        { NULL, NULL }
1.1       bouyer   1650: };
1.31      jdolecek 1651: const struct vnodeopv_desc ext2fs_fifoop_opv_desc =
1.1       bouyer   1652:        { &ext2fs_fifoop_p, ext2fs_fifoop_entries };

CVSweb <webmaster@jp.NetBSD.org>