[BACK]Return to ext2fs_vnops.c CVS log [TXT][DIR] Up to [local] / sys / ufs / ext2fs

Annotation of sys/ufs/ext2fs/ext2fs_vnops.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: ext2fs_vnops.c,v 1.48 2007/06/17 20:15:25 jasper Exp $        */
                      2: /*     $NetBSD: ext2fs_vnops.c,v 1.1 1997/06/11 09:34:09 bouyer Exp $  */
                      3:
                      4: /*
                      5:  * Copyright (c) 1997 Manuel Bouyer.
                      6:  * Copyright (c) 1982, 1986, 1989, 1993
                      7:  *     The Regents of the University of California.  All rights reserved.
                      8:  * (c) UNIX System Laboratories, Inc.
                      9:  * All or some portions of this file are derived from material licensed
                     10:  * to the University of California by American Telephone and Telegraph
                     11:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     12:  * the permission of UNIX System Laboratories, Inc.
                     13:  *
                     14:  * Redistribution and use in source and binary forms, with or without
                     15:  * modification, are permitted provided that the following conditions
                     16:  * are met:
                     17:  * 1. Redistributions of source code must retain the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer.
                     19:  * 2. Redistributions in binary form must reproduce the above copyright
                     20:  *    notice, this list of conditions and the following disclaimer in the
                     21:  *    documentation and/or other materials provided with the distribution.
                     22:  * 3. Neither the name of the University nor the names of its contributors
                     23:  *    may be used to endorse or promote products derived from this software
                     24:  *    without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     27:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     28:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     29:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     30:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     31:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     32:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     33:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     34:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     35:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     36:  * SUCH DAMAGE.
                     37:  *
                     38:  *     @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
                     39:  * Modified for ext2fs by Manuel Bouyer.
                     40:  */
                     41:
                     42: #include <sys/param.h>
                     43: #include <sys/systm.h>
                     44: #include <sys/resourcevar.h>
                     45: #include <sys/kernel.h>
                     46: #include <sys/file.h>
                     47: #include <sys/stat.h>
                     48: #include <sys/buf.h>
                     49: #include <sys/proc.h>
                     50: #include <sys/conf.h>
                     51: #include <sys/mount.h>
                     52: #include <sys/namei.h>
                     53: #include <sys/vnode.h>
                     54: #include <sys/lockf.h>
                     55: #include <sys/malloc.h>
                     56: #include <sys/pool.h>
                     57: #include <sys/signalvar.h>
                     58:
                     59: #include <uvm/uvm_extern.h>
                     60:
                     61: #include <miscfs/fifofs/fifo.h>
                     62: #include <miscfs/specfs/specdev.h>
                     63:
                     64: #include <ufs/ufs/quota.h>
                     65: #include <ufs/ufs/inode.h>
                     66: #include <ufs/ufs/ufs_extern.h>
                     67: #include <ufs/ufs/ufsmount.h>
                     68:
                     69: #include <ufs/ext2fs/ext2fs.h>
                     70: #include <ufs/ext2fs/ext2fs_extern.h>
                     71: #include <ufs/ext2fs/ext2fs_dir.h>
                     72:
                     73: static int ext2fs_chmod(struct vnode *, mode_t, struct ucred *, struct proc *);
                     74: static int ext2fs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct proc *);
                     75:
                     76: /*
                     77:  * Create a regular file
                     78:  */
                     79: int
                     80: ext2fs_create(void *v)
                     81: {
                     82:        struct vop_create_args *ap = v;
                     83:        return ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type,
                     84:                                          ap->a_vap->va_mode),
                     85:                                ap->a_dvp, ap->a_vpp, ap->a_cnp);
                     86: }
                     87:
                     88: /*
                     89:  * Mknod vnode call
                     90:  */
                     91: /* ARGSUSED */
                     92: int
                     93: ext2fs_mknod(void *v)
                     94: {
                     95:        struct vop_mknod_args *ap = v;
                     96:        struct vattr *vap = ap->a_vap;
                     97:        struct vnode **vpp = ap->a_vpp;
                     98:        struct inode *ip;
                     99:        int error;
                    100:
                    101:        if ((error =
                    102:                ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
                    103:                ap->a_dvp, vpp, ap->a_cnp)) != 0)
                    104:                return (error);
                    105:        ip = VTOI(*vpp);
                    106:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
                    107:        if (vap->va_rdev != VNOVAL) {
                    108:                /*
                    109:                 * Want to be able to use this to make badblock
                    110:                 * inodes, so don't truncate the dev number.
                    111:                 */
                    112:                ip->i_e2din->e2di_rdev = h2fs32(vap->va_rdev);
                    113:        }
                    114:        /*
                    115:         * Remove inode so that it will be reloaded by VFS_VGET and
                    116:         * checked to see if it is an alias of an existing entry in
                    117:         * the inode cache.
                    118:         */
                    119:        vput(*vpp);
                    120:        (*vpp)->v_type = VNON;
                    121:        vgone(*vpp);
                    122:        *vpp = 0;
                    123:        return (0);
                    124: }
                    125:
                    126: /*
                    127:  * Open called.
                    128:  *
                    129:  * Just check the APPEND flag.
                    130:  */
                    131: /* ARGSUSED */
                    132: int
                    133: ext2fs_open(void *v)
                    134: {
                    135:        struct vop_open_args *ap = v;
                    136:
                    137:        /*
                    138:         * Files marked append-only must be opened for appending.
                    139:         */
                    140:        if ((VTOI(ap->a_vp)->i_e2fs_flags & EXT2_APPEND) &&
                    141:                (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
                    142:                return (EPERM);
                    143:        return (0);
                    144: }
                    145:
                    146: int
                    147: ext2fs_access(void *v)
                    148: {
                    149:        struct vop_access_args *ap = v;
                    150:        struct vnode *vp = ap->a_vp;
                    151:        struct inode *ip = VTOI(vp);
                    152:        mode_t mode = ap->a_mode;
                    153:
                    154:        /* If immutable bit set, nobody gets to write it. */
                    155:        if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE))
                    156:                return (EPERM);
                    157:
                    158:        return (vaccess(ip->i_e2fs_mode, ip->i_e2fs_uid, ip->i_e2fs_gid, mode,
                    159:                        ap->a_cred));
                    160: }
                    161:
                    162: /* ARGSUSED */
                    163: int
                    164: ext2fs_getattr(void *v)
                    165: {
                    166:        struct vop_getattr_args *ap = v;
                    167:        struct vnode *vp = ap->a_vp;
                    168:        struct inode *ip = VTOI(vp);
                    169:        struct vattr *vap = ap->a_vap;
                    170:        struct timeval tv;
                    171:
                    172:        getmicrotime(&tv);
                    173:        EXT2FS_ITIMES(ip, &tv, &tv);
                    174:        /*
                    175:         * Copy from inode table
                    176:         */
                    177:        vap->va_fsid = ip->i_dev;
                    178:        vap->va_fileid = ip->i_number;
                    179:        vap->va_mode = ip->i_e2fs_mode & ALLPERMS;
                    180:        vap->va_nlink = ip->i_e2fs_nlink;
                    181:        vap->va_uid = ip->i_e2fs_uid;
                    182:        vap->va_gid = ip->i_e2fs_gid;
                    183:        vap->va_rdev = (dev_t)fs2h32(ip->i_e2din->e2di_rdev);
                    184:        vap->va_size = ext2fs_size(ip);
                    185:        vap->va_atime.tv_sec = ip->i_e2fs_atime;
                    186:        vap->va_atime.tv_nsec = 0;
                    187:        vap->va_mtime.tv_sec = ip->i_e2fs_mtime;
                    188:        vap->va_mtime.tv_nsec = 0;
                    189:        vap->va_ctime.tv_sec = ip->i_e2fs_ctime;
                    190:        vap->va_ctime.tv_nsec = 0;
                    191: #ifdef EXT2FS_SYSTEM_FLAGS
                    192:        vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0;
                    193:        vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
                    194: #else
                    195:        vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? UF_APPEND : 0;
                    196:        vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? UF_IMMUTABLE : 0;
                    197: #endif
                    198:        vap->va_gen = ip->i_e2fs_gen;
                    199:        /* this doesn't belong here */
                    200:        if (vp->v_type == VBLK)
                    201:                vap->va_blocksize = BLKDEV_IOSIZE;
                    202:        else if (vp->v_type == VCHR)
                    203:                vap->va_blocksize = MAXBSIZE;
                    204:        else
                    205:                vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
                    206:        vap->va_bytes = dbtob((u_quad_t)ip->i_e2fs_nblock);
                    207:        vap->va_type = vp->v_type;
                    208:        vap->va_filerev = ip->i_modrev;
                    209:        return (0);
                    210: }
                    211:
                    212: /*
                    213:  * Set attribute vnode op. called from several syscalls
                    214:  */
                    215: int
                    216: ext2fs_setattr(void *v)
                    217: {
                    218:        struct vop_setattr_args *ap = v;
                    219:        struct vattr *vap = ap->a_vap;
                    220:        struct vnode *vp = ap->a_vp;
                    221:        struct inode *ip = VTOI(vp);
                    222:        struct ucred *cred = ap->a_cred;
                    223:        struct proc *p = ap->a_p;
                    224:        int error;
                    225:
                    226:        /*
                    227:         * Check for unsettable attributes.
                    228:         */
                    229:        if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
                    230:                (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
                    231:                (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
                    232:                ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
                    233:                return (EINVAL);
                    234:        }
                    235:        if (vap->va_flags != VNOVAL) {
                    236:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    237:                        return (EROFS);
                    238:                if (cred->cr_uid != ip->i_e2fs_uid &&
                    239:                        (error = suser_ucred(cred)))
                    240:                        return (error);
                    241: #ifdef EXT2FS_SYSTEM_FLAGS
                    242:                if (cred->cr_uid == 0) {
                    243:                        if ((ip->i_e2fs_flags &
                    244:                            (EXT2_APPEND | EXT2_IMMUTABLE)) && securelevel > 0)
                    245:                                return (EPERM);
                    246:                        ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
                    247:                        ip->i_e2fs_flags |=
                    248:                            (vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 |
                    249:                            (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
                    250:                } else {
                    251:                        return (EPERM);
                    252:                }
                    253: #else
                    254:                ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
                    255:                ip->i_e2fs_flags |=
                    256:                    (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
                    257:                    (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
                    258: #endif
                    259:                ip->i_flag |= IN_CHANGE;
                    260:                if (vap->va_flags & (IMMUTABLE | APPEND))
                    261:                        return (0);
                    262:        }
                    263:        if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE))
                    264:                return (EPERM);
                    265:        /*
                    266:         * Go through the fields and update iff not VNOVAL.
                    267:         */
                    268:        if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
                    269:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    270:                        return (EROFS);
                    271:                error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
                    272:                if (error)
                    273:                        return (error);
                    274:        }
                    275:        if (vap->va_size != VNOVAL) {
                    276:                /*
                    277:                 * Disallow write attempts on read-only file systems;
                    278:                 * unless the file is a socket, fifo, or a block or
                    279:                 * character device resident on the file system.
                    280:                 */
                    281:                switch (vp->v_type) {
                    282:                case VDIR:
                    283:                        return (EISDIR);
                    284:                case VLNK:
                    285:                case VREG:
                    286:                        if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    287:                                return (EROFS);
                    288:                default:
                    289:                        break;
                    290:                }
                    291:                error = ext2fs_truncate(ip, vap->va_size, 0, cred);
                    292:                if (error)
                    293:                        return (error);
                    294:        }
                    295:        if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
                    296:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    297:                        return (EROFS);
                    298:                if (cred->cr_uid != ip->i_e2fs_uid &&
                    299:                        (error = suser_ucred(cred)) &&
                    300:                        ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
                    301:                        (error = VOP_ACCESS(vp, VWRITE, cred, p))))
                    302:                        return (error);
                    303:                if (vap->va_atime.tv_sec != VNOVAL)
                    304:                        if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
                    305:                                ip->i_flag |= IN_ACCESS;
                    306:                if (vap->va_mtime.tv_sec != VNOVAL)
                    307:                        ip->i_flag |= IN_CHANGE | IN_UPDATE;
                    308:                error = ext2fs_update(ip, &vap->va_atime, &vap->va_mtime, 1);
                    309:                if (error)
                    310:                        return (error);
                    311:        }
                    312:        error = 0;
                    313:        if (vap->va_mode != (mode_t)VNOVAL) {
                    314:                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    315:                        return (EROFS);
                    316:                error = ext2fs_chmod(vp, (int)vap->va_mode, cred, p);
                    317:        }
                    318:        return (error);
                    319: }
                    320:
                    321: /*
                    322:  * Change the mode on a file.
                    323:  * Inode must be locked before calling.
                    324:  */
                    325: static int
                    326: ext2fs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred, struct proc *p)
                    327: {
                    328:        struct inode *ip = VTOI(vp);
                    329:        int error;
                    330:
                    331:        if (cred->cr_uid != ip->i_e2fs_uid && (error = suser_ucred(cred)))
                    332:                return (error);
                    333:        if (cred->cr_uid) {
                    334:                if (vp->v_type != VDIR && (mode & S_ISTXT))
                    335:                        return (EFTYPE);
                    336:                if (!groupmember(ip->i_e2fs_gid, cred) && (mode & ISGID))
                    337:                        return (EPERM);
                    338:        }
                    339:        ip->i_e2fs_mode &= ~ALLPERMS;
                    340:        ip->i_e2fs_mode |= (mode & ALLPERMS);
                    341:        ip->i_flag |= IN_CHANGE;
                    342:        if ((vp->v_flag & VTEXT) && (ip->i_e2fs_mode & S_ISTXT) == 0)
                    343:                (void) uvm_vnp_uncache(vp);
                    344:        return (0);
                    345: }
                    346:
                    347: /*
                    348:  * Perform chown operation on inode ip;
                    349:  * inode must be locked prior to call.
                    350:  */
                    351: static int
                    352: ext2fs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, struct proc *p)
                    353: {
                    354:        struct inode *ip = VTOI(vp);
                    355:        uid_t ouid;
                    356:        gid_t ogid;
                    357:        int error = 0;
                    358:
                    359:        if (uid == (uid_t)VNOVAL)
                    360:                uid = ip->i_e2fs_uid;
                    361:        if (gid == (gid_t)VNOVAL)
                    362:                gid = ip->i_e2fs_gid;
                    363:        /*
                    364:         * If we don't own the file, are trying to change the owner
                    365:         * of the file, or are not a member of the target group,
                    366:         * the caller must be superuser or the call fails.
                    367:         */
                    368:        if ((cred->cr_uid != ip->i_e2fs_uid || uid != ip->i_e2fs_uid ||
                    369:                (gid != ip->i_e2fs_gid && !groupmember((gid_t)gid, cred))) &&
                    370:                (error = suser_ucred(cred)))
                    371:                return (error);
                    372:        ogid = ip->i_e2fs_gid;
                    373:        ouid = ip->i_e2fs_uid;
                    374:
                    375:        ip->i_e2fs_gid = gid;
                    376:        ip->i_e2fs_uid = uid;
                    377:        if (ouid != uid || ogid != gid)
                    378:                ip->i_flag |= IN_CHANGE;
                    379:        if (ouid != uid && cred->cr_uid != 0)
                    380:                ip->i_e2fs_mode &= ~ISUID;
                    381:        if (ogid != gid && cred->cr_uid != 0)
                    382:                ip->i_e2fs_mode &= ~ISGID;
                    383:        return (0);
                    384: }
                    385:
                    386: int
                    387: ext2fs_remove(void *v)
                    388: {
                    389:        struct vop_remove_args *ap = v;
                    390:        struct inode *ip;
                    391:        struct vnode *vp = ap->a_vp;
                    392:        struct vnode *dvp = ap->a_dvp;
                    393:        int error;
                    394:
                    395:        ip = VTOI(vp);
                    396:        if (vp->v_type == VDIR ||
                    397:                (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
                    398:                (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) {
                    399:                error = EPERM;
                    400:                goto out;
                    401:        }
                    402:        error = ext2fs_dirremove(dvp, ap->a_cnp);
                    403:        if (error == 0) {
                    404:                ip->i_e2fs_nlink--;
                    405:                ip->i_flag |= IN_CHANGE;
                    406:        }
                    407: out:
                    408:        if (dvp == vp)
                    409:                vrele(vp);
                    410:        else
                    411:                vput(vp);
                    412:        vput(dvp);
                    413:        return (error);
                    414: }
                    415:
                    416: /*
                    417:  * link vnode call
                    418:  */
                    419: int
                    420: ext2fs_link(void *v)
                    421: {
                    422:        struct vop_link_args *ap = v;
                    423:        struct vnode *dvp = ap->a_dvp;
                    424:        struct vnode *vp = ap->a_vp;
                    425:        struct componentname *cnp = ap->a_cnp;
                    426:        struct proc *p = cnp->cn_proc;
                    427:        struct inode *ip;
                    428:        int error;
                    429:
                    430: #ifdef DIAGNOSTIC
                    431:        if ((cnp->cn_flags & HASBUF) == 0)
                    432:                panic("ext2fs_link: no name");
                    433: #endif
                    434:        if (vp->v_type == VDIR) {
                    435:                VOP_ABORTOP(dvp, cnp);
                    436:                error = EISDIR;
                    437:                goto out2;
                    438:        }
                    439:        if (dvp->v_mount != vp->v_mount) {
                    440:                VOP_ABORTOP(dvp, cnp);
                    441:                error = EXDEV;
                    442:                goto out2;
                    443:        }
                    444:        if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
                    445:                VOP_ABORTOP(dvp, cnp);
                    446:                goto out2;
                    447:        }
                    448:        ip = VTOI(vp);
                    449:        if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
                    450:                VOP_ABORTOP(dvp, cnp);
                    451:                error = EMLINK;
                    452:                goto out1;
                    453:        }
                    454:        if (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) {
                    455:                VOP_ABORTOP(dvp, cnp);
                    456:                error = EPERM;
                    457:                goto out1;
                    458:        }
                    459:        ip->i_e2fs_nlink++;
                    460:        ip->i_flag |= IN_CHANGE;
                    461:        error = ext2fs_update(ip, NULL, NULL, 1);
                    462:        if (!error)
                    463:                error = ext2fs_direnter(ip, dvp, cnp);
                    464:        if (error) {
                    465:                ip->i_e2fs_nlink--;
                    466:                ip->i_flag |= IN_CHANGE;
                    467:        }
                    468:        pool_put(&namei_pool, cnp->cn_pnbuf);
                    469: out1:
                    470:        if (dvp != vp)
                    471:                VOP_UNLOCK(vp, 0, p);
                    472: out2:
                    473:        vput(dvp);
                    474:        return (error);
                    475: }
                    476:
                    477: /*
                    478:  * Rename system call.
                    479:  *     rename("foo", "bar");
                    480:  * is essentially
                    481:  *     unlink("bar");
                    482:  *     link("foo", "bar");
                    483:  *     unlink("foo");
                    484:  * but ``atomically''.  Can't do full commit without saving state in the
                    485:  * inode on disk which isn't feasible at this time.  Best we can do is
                    486:  * always guarantee the target exists.
                    487:  *
                    488:  * Basic algorithm is:
                    489:  *
                    490:  * 1) Bump link count on source while we're linking it to the
                    491:  *    target.  This also ensure the inode won't be deleted out
                    492:  *    from underneath us while we work (it may be truncated by
                    493:  *    a concurrent `trunc' or `open' for creation).
                    494:  * 2) Link source to destination.  If destination already exists,
                    495:  *    delete it first.
                    496:  * 3) Unlink source reference to inode if still around. If a
                    497:  *    directory was moved and the parent of the destination
                    498:  *    is different from the source, patch the ".." entry in the
                    499:  *    directory.
                    500:  */
                    501: int
                    502: ext2fs_rename(void *v)
                    503: {
                    504:        struct vop_rename_args  *ap = v;
                    505:        struct vnode *tvp = ap->a_tvp;
                    506:        struct vnode *tdvp = ap->a_tdvp;
                    507:        struct vnode *fvp = ap->a_fvp;
                    508:        struct vnode *fdvp = ap->a_fdvp;
                    509:        struct componentname *tcnp = ap->a_tcnp;
                    510:        struct componentname *fcnp = ap->a_fcnp;
                    511:        struct inode *ip, *xp, *dp;
                    512:        struct proc *p = fcnp->cn_proc;
                    513:        struct ext2fs_dirtemplate dirbuf;
                    514:        /* struct timespec ts; */
                    515:        int doingdirectory = 0, oldparent = 0, newparent = 0;
                    516:        int error = 0;
                    517:        u_char namlen;
                    518:
                    519: #ifdef DIAGNOSTIC
                    520:        if ((tcnp->cn_flags & HASBUF) == 0 ||
                    521:            (fcnp->cn_flags & HASBUF) == 0)
                    522:                panic("ext2fs_rename: no name");
                    523: #endif
                    524:        /*
                    525:         * Check for cross-device rename.
                    526:         */
                    527:        if ((fvp->v_mount != tdvp->v_mount) ||
                    528:            (tvp && (fvp->v_mount != tvp->v_mount))) {
                    529:                error = EXDEV;
                    530: abortit:
                    531:                VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
                    532:                if (tdvp == tvp)
                    533:                        vrele(tdvp);
                    534:                else
                    535:                        vput(tdvp);
                    536:                if (tvp)
                    537:                        vput(tvp);
                    538:                VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
                    539:                vrele(fdvp);
                    540:                vrele(fvp);
                    541:                return (error);
                    542:        }
                    543:
                    544:        /*
                    545:         * Check if just deleting a link name.
                    546:         */
                    547:        if (tvp && ((VTOI(tvp)->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
                    548:            (VTOI(tdvp)->i_e2fs_flags & EXT2_APPEND))) {
                    549:                error = EPERM;
                    550:                goto abortit;
                    551:        }
                    552:        if (fvp == tvp) {
                    553:                if (fvp->v_type == VDIR) {
                    554:                        error = EINVAL;
                    555:                        goto abortit;
                    556:                }
                    557:
                    558:                /* Release destination completely. */
                    559:                VOP_ABORTOP(tdvp, tcnp);
                    560:                vput(tdvp);
                    561:                vput(tvp);
                    562:
                    563:                /* Delete source. */
                    564:                vrele(fdvp);
                    565:                vrele(fvp);
                    566:                fcnp->cn_flags &= ~MODMASK;
                    567:                fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
                    568:                if ((fcnp->cn_flags & SAVESTART) == 0)
                    569:                        panic("ext2fs_rename: lost from startdir");
                    570:                fcnp->cn_nameiop = DELETE;
                    571:                (void) relookup(fdvp, &fvp, fcnp);
                    572:                return (VOP_REMOVE(fdvp, fvp, fcnp));
                    573:        }
                    574:        if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
                    575:                goto abortit;
                    576:        dp = VTOI(fdvp);
                    577:        ip = VTOI(fvp);
                    578:        if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
                    579:                VOP_UNLOCK(fvp, 0, p);
                    580:                error = EMLINK;
                    581:                goto abortit;
                    582:        }
                    583:        if ((ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
                    584:                (dp->i_e2fs_flags & EXT2_APPEND)) {
                    585:                VOP_UNLOCK(fvp, 0, p);
                    586:                error = EPERM;
                    587:                goto abortit;
                    588:        }
                    589:        if ((ip->i_e2fs_mode & IFMT) == IFDIR) {
                    590:                error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
                    591:                if (!error && tvp)
                    592:                        error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred,
                    593:                            tcnp->cn_proc);
                    594:                if (error) {
                    595:                        VOP_UNLOCK(fvp, 0, p);
                    596:                        error = EACCES;
                    597:                        goto abortit;
                    598:                }
                    599:                /*
                    600:                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                    601:                 */
                    602:                if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
                    603:                    dp == ip ||
                    604:                        (fcnp->cn_flags&ISDOTDOT) ||
                    605:                        (tcnp->cn_flags & ISDOTDOT) ||
                    606:                    (ip->i_flag & IN_RENAME)) {
                    607:                        VOP_UNLOCK(fvp, 0, p);
                    608:                        error = EINVAL;
                    609:                        goto abortit;
                    610:                }
                    611:                ip->i_flag |= IN_RENAME;
                    612:                oldparent = dp->i_number;
                    613:                doingdirectory++;
                    614:        }
                    615:        vrele(fdvp);
                    616:
                    617:        /*
                    618:         * When the target exists, both the directory
                    619:         * and target vnodes are returned locked.
                    620:         */
                    621:        dp = VTOI(tdvp);
                    622:        xp = NULL;
                    623:        if (tvp)
                    624:                xp = VTOI(tvp);
                    625:
                    626:        /*
                    627:         * 1) Bump link count while we're moving stuff
                    628:         *    around.  If we crash somewhere before
                    629:         *    completing our work, the link count
                    630:         *    may be wrong, but correctable.
                    631:         */
                    632:        ip->i_e2fs_nlink++;
                    633:        ip->i_flag |= IN_CHANGE;
                    634:        if ((error = ext2fs_update(ip, NULL, NULL, 1)) != 0) {
                    635:                VOP_UNLOCK(fvp, 0, p);
                    636:                goto bad;
                    637:        }
                    638:
                    639:        /*
                    640:         * If ".." must be changed (ie the directory gets a new
                    641:         * parent) then the source directory must not be in the
                    642:         * directory hierarchy above the target, as this would
                    643:         * orphan everything below the source directory. Also
                    644:         * the user must have write permission in the source so
                    645:         * as to be able to change "..". We must repeat the call
                    646:         * to namei, as the parent directory is unlocked by the
                    647:         * call to checkpath().
                    648:         */
                    649:        error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
                    650:        VOP_UNLOCK(fvp, 0, p);
                    651:        if (oldparent != dp->i_number)
                    652:                newparent = dp->i_number;
                    653:        if (doingdirectory && newparent) {
                    654:                if (error)      /* write access check above */
                    655:                        goto bad;
                    656:                if (xp != NULL)
                    657:                        vput(tvp);
                    658:                error = ext2fs_checkpath(ip, dp, tcnp->cn_cred);
                    659:                if (error != 0)
                    660:                        goto out;
                    661:                if ((tcnp->cn_flags & SAVESTART) == 0)
                    662:                        panic("ext2fs_rename: lost to startdir");
                    663:                if ((error = relookup(tdvp, &tvp, tcnp)) != 0)
                    664:                        goto out;
                    665:                dp = VTOI(tdvp);
                    666:                xp = NULL;
                    667:                if (tvp)
                    668:                        xp = VTOI(tvp);
                    669:        }
                    670:        /*
                    671:         * 2) If target doesn't exist, link the target
                    672:         *    to the source and unlink the source.
                    673:         *    Otherwise, rewrite the target directory
                    674:         *    entry to reference the source inode and
                    675:         *    expunge the original entry's existence.
                    676:         */
                    677:        if (xp == NULL) {
                    678:                if (dp->i_dev != ip->i_dev)
                    679:                        panic("rename: EXDEV");
                    680:                /*
                    681:                 * Account for ".." in new directory.
                    682:                 * When source and destination have the same
                    683:                 * parent we don't fool with the link count.
                    684:                 */
                    685:                if (doingdirectory && newparent) {
                    686:                        if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
                    687:                                error = EMLINK;
                    688:                                goto bad;
                    689:                        }
                    690:                        dp->i_e2fs_nlink++;
                    691:                        dp->i_flag |= IN_CHANGE;
                    692:                        if ((error = ext2fs_update(dp, NULL, NULL, 1)) != 0)
                    693:                                goto bad;
                    694:                }
                    695:                error = ext2fs_direnter(ip, tdvp, tcnp);
                    696:                if (error != 0) {
                    697:                        if (doingdirectory && newparent) {
                    698:                                dp->i_e2fs_nlink--;
                    699:                                dp->i_flag |= IN_CHANGE;
                    700:                                (void)ext2fs_update(dp, NULL, NULL, 1);
                    701:                        }
                    702:                        goto bad;
                    703:                }
                    704:                vput(tdvp);
                    705:        } else {
                    706:                if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
                    707:                        panic("rename: EXDEV");
                    708:                /*
                    709:                 * Short circuit rename(foo, foo).
                    710:                 */
                    711:                if (xp->i_number == ip->i_number)
                    712:                        panic("rename: same file");
                    713:                /*
                    714:                 * If the parent directory is "sticky", then the user must
                    715:                 * own the parent directory, or the destination of the rename,
                    716:                 * otherwise the destination may not be changed (except by
                    717:                 * root). This implements append-only directories.
                    718:                 */
                    719:                if ((dp->i_e2fs_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
                    720:                    tcnp->cn_cred->cr_uid != dp->i_e2fs_uid &&
                    721:                    xp->i_e2fs_uid != tcnp->cn_cred->cr_uid) {
                    722:                        error = EPERM;
                    723:                        goto bad;
                    724:                }
                    725:                /*
                    726:                 * Target must be empty if a directory and have no links
                    727:                 * to it. Also, ensure source and target are compatible
                    728:                 * (both directories, or both not directories).
                    729:                 */
                    730:                if ((xp->i_e2fs_mode & IFMT) == IFDIR) {
                    731:                        if (!ext2fs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
                    732:                                xp->i_e2fs_nlink > 2) {
                    733:                                error = ENOTEMPTY;
                    734:                                goto bad;
                    735:                        }
                    736:                        if (!doingdirectory) {
                    737:                                error = ENOTDIR;
                    738:                                goto bad;
                    739:                        }
                    740:                        cache_purge(tdvp);
                    741:                } else if (doingdirectory) {
                    742:                        error = EISDIR;
                    743:                        goto bad;
                    744:                }
                    745:                error = ext2fs_dirrewrite(dp, ip, tcnp);
                    746:                if (error != 0)
                    747:                        goto bad;
                    748:                /*
                    749:                 * If the target directory is in the same
                    750:                 * directory as the source directory,
                    751:                 * decrement the link count on the parent
                    752:                 * of the target directory.
                    753:                 */
                    754:                 if (doingdirectory && !newparent) {
                    755:                        dp->i_e2fs_nlink--;
                    756:                        dp->i_flag |= IN_CHANGE;
                    757:                }
                    758:                vput(tdvp);
                    759:                /*
                    760:                 * Adjust the link count of the target to
                    761:                 * reflect the dirrewrite above.  If this is
                    762:                 * a directory it is empty and there are
                    763:                 * no links to it, so we can squash the inode and
                    764:                 * any space associated with it.  We disallowed
                    765:                 * renaming over top of a directory with links to
                    766:                 * it above, as the remaining link would point to
                    767:                 * a directory without "." or ".." entries.
                    768:                 */
                    769:                xp->i_e2fs_nlink--;
                    770:                if (doingdirectory) {
                    771:                        if (--xp->i_e2fs_nlink != 0)
                    772:                                panic("rename: linked directory");
                    773:                        error = ext2fs_truncate(xp, (off_t)0, IO_SYNC,
                    774:                            tcnp->cn_cred);
                    775:                }
                    776:                xp->i_flag |= IN_CHANGE;
                    777:                vput(tvp);
                    778:                xp = NULL;
                    779:        }
                    780:
                    781:        /*
                    782:         * 3) Unlink the source.
                    783:         */
                    784:        fcnp->cn_flags &= ~MODMASK;
                    785:        fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
                    786:        if ((fcnp->cn_flags & SAVESTART) == 0)
                    787:                panic("ext2fs_rename: lost from startdir");
                    788:        (void) relookup(fdvp, &fvp, fcnp);
                    789:        if (fvp != NULL) {
                    790:                xp = VTOI(fvp);
                    791:                dp = VTOI(fdvp);
                    792:        } else {
                    793:                /*
                    794:                 * From name has disappeared.
                    795:                 */
                    796:                if (doingdirectory)
                    797:                        panic("ext2fs_rename: lost dir entry");
                    798:                vrele(ap->a_fvp);
                    799:                return (0);
                    800:        }
                    801:        /*
                    802:         * Ensure that the directory entry still exists and has not
                    803:         * changed while the new name has been entered. If the source is
                    804:         * a file then the entry may have been unlinked or renamed. In
                    805:         * either case there is no further work to be done. If the source
                    806:         * is a directory then it cannot have been rmdir'ed; its link
                    807:         * count of three would cause a rmdir to fail with ENOTEMPTY.
                    808:         * The IRENAME flag ensures that it cannot be moved by another
                    809:         * rename.
                    810:         */
                    811:        if (xp != ip) {
                    812:                if (doingdirectory)
                    813:                        panic("ext2fs_rename: lost dir entry");
                    814:        } else {
                    815:                /*
                    816:                 * If the source is a directory with a
                    817:                 * new parent, the link count of the old
                    818:                 * parent directory must be decremented
                    819:                 * and ".." set to point to the new parent.
                    820:                 */
                    821:                if (doingdirectory && newparent) {
                    822:                        dp->i_e2fs_nlink--;
                    823:                        dp->i_flag |= IN_CHANGE;
                    824:                        error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
                    825:                                sizeof (struct ext2fs_dirtemplate), (off_t)0,
                    826:                                UIO_SYSSPACE, IO_NODELOCKED,
                    827:                                tcnp->cn_cred, (size_t *)0, (struct proc *)0);
                    828:                        if (error == 0) {
                    829:                                        namlen = dirbuf.dotdot_namlen;
                    830:                                if (namlen != 2 ||
                    831:                                    dirbuf.dotdot_name[0] != '.' ||
                    832:                                    dirbuf.dotdot_name[1] != '.') {
                    833:                                        ufs_dirbad(xp, (doff_t)12,
                    834:                                            "ext2fs_rename: mangled dir");
                    835:                                } else {
                    836:                                        dirbuf.dotdot_ino = h2fs32(newparent);
                    837:                                        (void) vn_rdwr(UIO_WRITE, fvp,
                    838:                                            (caddr_t)&dirbuf,
                    839:                                            sizeof (struct dirtemplate),
                    840:                                            (off_t)0, UIO_SYSSPACE,
                    841:                                            IO_NODELOCKED|IO_SYNC,
                    842:                                            tcnp->cn_cred, (size_t *)0,
                    843:                                            (struct proc *)0);
                    844:                                        cache_purge(fdvp);
                    845:                                }
                    846:                        }
                    847:                }
                    848:                error = ext2fs_dirremove(fdvp, fcnp);
                    849:                if (!error) {
                    850:                        xp->i_e2fs_nlink--;
                    851:                        xp->i_flag |= IN_CHANGE;
                    852:                }
                    853:                xp->i_flag &= ~IN_RENAME;
                    854:        }
                    855:        if (dp)
                    856:                vput(fdvp);
                    857:        if (xp)
                    858:                vput(fvp);
                    859:        vrele(ap->a_fvp);
                    860:        return (error);
                    861:
                    862: bad:
                    863:        if (xp)
                    864:                vput(ITOV(xp));
                    865:        vput(ITOV(dp));
                    866: out:
                    867:        if (doingdirectory)
                    868:                ip->i_flag &= ~IN_RENAME;
                    869:        if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) {
                    870:                ip->i_e2fs_nlink--;
                    871:                ip->i_flag |= IN_CHANGE;
                    872:                vput(fvp);
                    873:        } else
                    874:                vrele(fvp);
                    875:        return (error);
                    876: }
                    877:
                    878: /*
                    879:  * Mkdir system call
                    880:  */
                    881: int
                    882: ext2fs_mkdir(void *v)
                    883: {
                    884:        struct vop_mkdir_args *ap = v;
                    885:        struct vnode *dvp = ap->a_dvp;
                    886:        struct vattr *vap = ap->a_vap;
                    887:        struct componentname *cnp = ap->a_cnp;
                    888:        struct inode *ip, *dp;
                    889:        struct vnode *tvp;
                    890:        struct ext2fs_dirtemplate dirtemplate;
                    891:        mode_t dmode;
                    892:        int error;
                    893:
                    894: #ifdef DIAGNOSTIC
                    895:        if ((cnp->cn_flags & HASBUF) == 0)
                    896:                panic("ext2fs_mkdir: no name");
                    897: #endif
                    898:        dp = VTOI(dvp);
                    899:        if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
                    900:                error = EMLINK;
                    901:                goto out;
                    902:        }
                    903:        dmode = vap->va_mode & ACCESSPERMS;
                    904:        dmode |= IFDIR;
                    905:        /*
                    906:         * Must simulate part of ext2fs_makeinode here to acquire the inode,
                    907:         * but not have it entered in the parent directory. The entry is
                    908:         * made later after writing "." and ".." entries.
                    909:         */
                    910:        if ((error = ext2fs_inode_alloc(dp, dmode, cnp->cn_cred, &tvp)) != 0)
                    911:                goto out;
                    912:        ip = VTOI(tvp);
                    913:        ip->i_e2fs_uid = cnp->cn_cred->cr_uid;
                    914:        ip->i_e2fs_gid = dp->i_e2fs_gid;
                    915:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
                    916:        ip->i_e2fs_mode = dmode;
                    917:        tvp->v_type = VDIR;     /* Rest init'd in getnewvnode(). */
                    918:        ip->i_e2fs_nlink = 2;
                    919:        error = ext2fs_update(ip, NULL, NULL, 1);
                    920:
                    921:        /*
                    922:         * Bump link count in parent directory
                    923:         * to reflect work done below.  Should
                    924:         * be done before reference is created
                    925:         * so reparation is possible if we crash.
                    926:         */
                    927:        dp->i_e2fs_nlink++;
                    928:        dp->i_flag |= IN_CHANGE;
                    929:        if ((error = ext2fs_update(dp, NULL, NULL, 1)) != 0)
                    930:                goto bad;
                    931:
                    932:        /* Initialize directory with "." and ".." from static template. */
                    933:        bzero(&dirtemplate, sizeof(dirtemplate));
                    934:        dirtemplate.dot_ino = h2fs32(ip->i_number);
                    935:        dirtemplate.dot_reclen = h2fs16(12);
                    936:        dirtemplate.dot_namlen = 1;
                    937:        if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
                    938:            (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
                    939:                dirtemplate.dot_type = EXT2_FT_DIR;
                    940:        }
                    941:        dirtemplate.dot_name[0] = '.';
                    942:        dirtemplate.dotdot_ino = h2fs32(dp->i_number);
                    943:        dirtemplate.dotdot_reclen = h2fs16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12);
                    944:        dirtemplate.dotdot_namlen = 2;
                    945:        if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
                    946:            (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
                    947:                dirtemplate.dotdot_type = EXT2_FT_DIR;
                    948:        }
                    949:        dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
                    950:        error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
                    951:            sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
                    952:            IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (size_t *)0, (struct proc *)0);
                    953:        if (error) {
                    954:                dp->i_e2fs_nlink--;
                    955:                dp->i_flag |= IN_CHANGE;
                    956:                goto bad;
                    957:        }
                    958:        if (VTOI(dvp)->i_e2fs->e2fs_bsize >
                    959:                                                        VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
                    960:                panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */
                    961:        else {
                    962:                error = ext2fs_setsize(ip, VTOI(dvp)->i_e2fs->e2fs_bsize);
                    963:                if (error) {
                    964:                        dp->i_e2fs_nlink--;
                    965:                        dp->i_flag |= IN_CHANGE;
                    966:                        goto bad;
                    967:                }
                    968:                ip->i_flag |= IN_CHANGE;
                    969:        }
                    970:
                    971:        /* Directory set up, now install its entry in the parent directory. */
                    972:        error = ext2fs_direnter(ip, dvp, cnp);
                    973:        if (error != 0) {
                    974:                dp->i_e2fs_nlink--;
                    975:                dp->i_flag |= IN_CHANGE;
                    976:        }
                    977: bad:
                    978:        /*
                    979:         * No need to do an explicit VOP_TRUNCATE here, vrele will do this
                    980:         * for us because we set the link count to 0.
                    981:         */
                    982:        if (error) {
                    983:                ip->i_e2fs_nlink = 0;
                    984:                ip->i_flag |= IN_CHANGE;
                    985:                vput(tvp);
                    986:        } else
                    987:                *ap->a_vpp = tvp;
                    988: out:
                    989:        pool_put(&namei_pool, cnp->cn_pnbuf);
                    990:        vput(dvp);
                    991:        return (error);
                    992: }
                    993:
                    994: /*
                    995:  * Rmdir system call.
                    996:  */
                    997: int
                    998: ext2fs_rmdir(void *v)
                    999: {
                   1000:        struct vop_rmdir_args *ap = v;
                   1001:        struct vnode *vp = ap->a_vp;
                   1002:        struct vnode *dvp = ap->a_dvp;
                   1003:        struct componentname *cnp = ap->a_cnp;
                   1004:        struct inode *ip, *dp;
                   1005:        int error;
                   1006:
                   1007:        ip = VTOI(vp);
                   1008:        dp = VTOI(dvp);
                   1009:        /*
                   1010:         * No rmdir "." please.
                   1011:         */
                   1012:        if (dp == ip) {
                   1013:                vrele(dvp);
                   1014:                vput(vp);
                   1015:                return (EINVAL);
                   1016:        }
                   1017:        /*
                   1018:         * Verify the directory is empty (and valid).
                   1019:         * (Rmdir ".." won't be valid since
                   1020:         *  ".." will contain a reference to
                   1021:         *  the current directory and thus be
                   1022:         *  non-empty.)
                   1023:         */
                   1024:        error = 0;
                   1025:        if (ip->i_e2fs_nlink != 2 ||
                   1026:            !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
                   1027:                error = ENOTEMPTY;
                   1028:                goto out;
                   1029:        }
                   1030:        if ((dp->i_e2fs_flags & EXT2_APPEND) ||
                   1031:                                 (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) {
                   1032:                error = EPERM;
                   1033:                goto out;
                   1034:        }
                   1035:        /*
                   1036:         * Delete reference to directory before purging
                   1037:         * inode.  If we crash in between, the directory
                   1038:         * will be reattached to lost+found,
                   1039:         */
                   1040:        error = ext2fs_dirremove(dvp, cnp);
                   1041:        if (error != 0)
                   1042:                goto out;
                   1043:        dp->i_e2fs_nlink--;
                   1044:        dp->i_flag |= IN_CHANGE;
                   1045:        cache_purge(dvp);
                   1046:        vput(dvp);
                   1047:        dvp = NULL;
                   1048:        /*
                   1049:         * Truncate inode.  The only stuff left
                   1050:         * in the directory is "." and "..".  The
                   1051:         * "." reference is inconsequential since
                   1052:         * we're quashing it.  The ".." reference
                   1053:         * has already been adjusted above.  We've
                   1054:         * removed the "." reference and the reference
                   1055:         * in the parent directory, but there may be
                   1056:         * other hard links so decrement by 2 and
                   1057:         * worry about them later.
                   1058:         */
                   1059:        ip->i_e2fs_nlink -= 2;
                   1060:        error = ext2fs_truncate(ip, (off_t)0, IO_SYNC, cnp->cn_cred);
                   1061:        cache_purge(ITOV(ip));
                   1062: out:
                   1063:        if (dvp)
                   1064:                vput(dvp);
                   1065:        vput(vp);
                   1066:        return (error);
                   1067: }
                   1068:
                   1069: /*
                   1070:  * symlink -- make a symbolic link
                   1071:  */
                   1072: int
                   1073: ext2fs_symlink(void *v)
                   1074: {
                   1075:        struct vop_symlink_args *ap = v;
                   1076:        struct vnode *vp, **vpp = ap->a_vpp;
                   1077:        struct inode *ip;
                   1078:        int len, error;
                   1079:
                   1080:        error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
                   1081:                              vpp, ap->a_cnp);
                   1082:        if (error)
                   1083:                return (error);
                   1084:        vp = *vpp;
                   1085:        len = strlen(ap->a_target);
                   1086:        if (len < vp->v_mount->mnt_maxsymlinklen) {
                   1087:                ip = VTOI(vp);
                   1088:                bcopy(ap->a_target, (char *)ip->i_e2din->e2di_shortlink, len);
                   1089:                error = ext2fs_setsize(ip, len);
                   1090:                if (error)
                   1091:                        goto bad;
                   1092:                ip->i_flag |= IN_CHANGE | IN_UPDATE;
                   1093:        } else
                   1094:                error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
                   1095:                    UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, NULL,
                   1096:                    (struct proc *)0);
                   1097: bad:
                   1098:        vput(vp);
                   1099:        return (error);
                   1100: }
                   1101:
                   1102: /*
                   1103:  * Return target name of a symbolic link
                   1104:  */
                   1105: int
                   1106: ext2fs_readlink(void *v)
                   1107: {
                   1108:        struct vop_readlink_args *ap = v;
                   1109:        struct vnode *vp = ap->a_vp;
                   1110:        struct inode *ip = VTOI(vp);
                   1111:        int isize;
                   1112:
                   1113:        isize = ext2fs_size(ip);
                   1114:        if (isize < vp->v_mount->mnt_maxsymlinklen ||
                   1115:            (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) {
                   1116:                uiomove((char *)ip->i_e2din->e2di_shortlink, isize, ap->a_uio);
                   1117:                return (0);
                   1118:        }
                   1119:        return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
                   1120: }
                   1121:
                   1122: /*
                   1123:  * Advisory record locking support
                   1124:  */
                   1125: int
                   1126: ext2fs_advlock(void *v)
                   1127: {
                   1128:        struct vop_advlock_args *ap = v;
                   1129:        struct inode *ip = VTOI(ap->a_vp);
                   1130:
                   1131:        return (lf_advlock(&ip->i_lockf, ext2fs_size(ip), ap->a_id, ap->a_op,
                   1132:            ap->a_fl, ap->a_flags));
                   1133: }
                   1134:
                   1135: /*
                   1136:  * Allocate a new inode.
                   1137:  */
                   1138: int
                   1139: ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
                   1140:     struct componentname *cnp)
                   1141: {
                   1142:        struct inode *ip, *pdir;
                   1143:        struct vnode *tvp;
                   1144:        int error;
                   1145:
                   1146:        pdir = VTOI(dvp);
                   1147: #ifdef DIAGNOSTIC
                   1148:        if ((cnp->cn_flags & HASBUF) == 0)
                   1149:                panic("ext2fs_makeinode: no name");
                   1150: #endif
                   1151:        *vpp = NULL;
                   1152:        if ((mode & IFMT) == 0)
                   1153:                mode |= IFREG;
                   1154:
                   1155:        if ((error = ext2fs_inode_alloc(pdir, mode, cnp->cn_cred, &tvp))
                   1156:            != 0) {
                   1157:                pool_put(&namei_pool, cnp->cn_pnbuf);
                   1158:                vput(dvp);
                   1159:                return (error);
                   1160:        }
                   1161:        ip = VTOI(tvp);
                   1162:        ip->i_e2fs_gid = pdir->i_e2fs_gid;
                   1163:        ip->i_e2fs_uid = cnp->cn_cred->cr_uid;
                   1164:        ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
                   1165:        ip->i_e2fs_mode = mode;
                   1166:        tvp->v_type = IFTOVT(mode);     /* Rest init'd in getnewvnode(). */
                   1167:        ip->i_e2fs_nlink = 1;
                   1168:        if ((ip->i_e2fs_mode & ISGID) &&
                   1169:                !groupmember(ip->i_e2fs_gid, cnp->cn_cred) &&
                   1170:            suser_ucred(cnp->cn_cred))
                   1171:                ip->i_e2fs_mode &= ~ISGID;
                   1172:
                   1173:        /*
                   1174:         * Make sure inode goes to disk before directory entry.
                   1175:         */
                   1176:        if ((error = ext2fs_update(ip, NULL, NULL, 1)) != 0)
                   1177:                goto bad;
                   1178:        error = ext2fs_direnter(ip, dvp, cnp);
                   1179:        if (error != 0)
                   1180:                goto bad;
                   1181:        if ((cnp->cn_flags & SAVESTART) == 0)
                   1182:                pool_put(&namei_pool, cnp->cn_pnbuf);
                   1183:        vput(dvp);
                   1184:        *vpp = tvp;
                   1185:        return (0);
                   1186:
                   1187: bad:
                   1188:        /*
                   1189:         * Write error occurred trying to update the inode
                   1190:         * or the directory so must deallocate the inode.
                   1191:         */
                   1192:        pool_put(&namei_pool, cnp->cn_pnbuf);
                   1193:        vput(dvp);
                   1194:        ip->i_e2fs_nlink = 0;
                   1195:        ip->i_flag |= IN_CHANGE;
                   1196:        tvp->v_type = VNON;
                   1197:        vput(tvp);
                   1198:        return (error);
                   1199: }
                   1200:
                   1201: /*
                   1202:  * Synch an open file.
                   1203:  */
                   1204: /* ARGSUSED */
                   1205: int
                   1206: ext2fs_fsync(void *v)
                   1207: {
                   1208:        struct vop_fsync_args *ap = v;
                   1209:        struct vnode *vp = ap->a_vp;
                   1210:
                   1211:        vflushbuf(vp, ap->a_waitfor == MNT_WAIT);
                   1212:        return (ext2fs_update(VTOI(ap->a_vp), NULL, NULL,
                   1213:                    ap->a_waitfor == MNT_WAIT));
                   1214: }
                   1215:
                   1216: /*
                   1217:  * Reclaim an inode so that it can be used for other purposes.
                   1218:  */
                   1219: int
                   1220: ext2fs_reclaim(void *v)
                   1221: {
                   1222:        struct vop_reclaim_args *ap = v;
                   1223:        struct vnode *vp = ap->a_vp;
                   1224:        struct inode *ip;
                   1225: #ifdef DIAGNOSTIC
                   1226:        extern int prtactive;
                   1227:
                   1228:        if (prtactive && vp->v_usecount != 0)
                   1229:                vprint("ext2fs_reclaim: pushing active", vp);
                   1230: #endif
                   1231:
                   1232:        /*
                   1233:         * Remove the inode from its hash chain.
                   1234:         */
                   1235:        ip = VTOI(vp);
                   1236:        ufs_ihashrem(ip);
                   1237:
                   1238:        /*
                   1239:         * Purge old data structures associated with the inode.
                   1240:         */
                   1241:        cache_purge(vp);
                   1242:        if (ip->i_devvp)
                   1243:                vrele(ip->i_devvp);
                   1244:
                   1245:        if (ip->i_e2din != NULL)
                   1246:                pool_put(&ext2fs_dinode_pool, ip->i_e2din);
                   1247:
                   1248:        pool_put(&ext2fs_inode_pool, ip);
                   1249:
                   1250:        vp->v_data = NULL;
                   1251:
                   1252:        return (0);
                   1253: }
                   1254:
                   1255: /* Global vfs data structures for ext2fs. */
                   1256: int (**ext2fs_vnodeop_p)(void *);
                   1257: struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = {
                   1258:        { &vop_default_desc, vn_default_error },
                   1259:        { &vop_lookup_desc, ext2fs_lookup },    /* lookup */
                   1260:        { &vop_create_desc, ext2fs_create },    /* create */
                   1261:        { &vop_mknod_desc, ext2fs_mknod },              /* mknod */
                   1262:        { &vop_open_desc, ext2fs_open },                /* open */
                   1263:        { &vop_close_desc, ufs_close },                 /* close */
                   1264:        { &vop_access_desc, ext2fs_access },    /* access */
                   1265:        { &vop_getattr_desc, ext2fs_getattr },  /* getattr */
                   1266:        { &vop_setattr_desc, ext2fs_setattr },  /* setattr */
                   1267:        { &vop_read_desc, ext2fs_read },                /* read */
                   1268:        { &vop_write_desc, ext2fs_write },              /* write */
                   1269:        { &vop_ioctl_desc, ufs_ioctl },                 /* ioctl */
                   1270:        { &vop_poll_desc, ufs_poll },           /* poll */
                   1271:        { &vop_kqfilter_desc, vop_generic_kqfilter },   /* kqfilter */
                   1272:        { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
                   1273:        { &vop_remove_desc, ext2fs_remove },    /* remove */
                   1274:        { &vop_link_desc, ext2fs_link },                /* link */
                   1275:        { &vop_rename_desc, ext2fs_rename },    /* rename */
                   1276:        { &vop_mkdir_desc, ext2fs_mkdir },              /* mkdir */
                   1277:        { &vop_rmdir_desc, ext2fs_rmdir },              /* rmdir */
                   1278:        { &vop_symlink_desc, ext2fs_symlink },  /* symlink */
                   1279:        { &vop_readdir_desc, ext2fs_readdir },  /* readdir */
                   1280:        { &vop_readlink_desc, ext2fs_readlink },/* readlink */
                   1281:        { &vop_abortop_desc, vop_generic_abortop },             /* abortop */
                   1282:        { &vop_inactive_desc, ext2fs_inactive },/* inactive */
                   1283:        { &vop_reclaim_desc, ext2fs_reclaim },  /* reclaim */
                   1284:        { &vop_lock_desc, ufs_lock },                   /* lock */
                   1285:        { &vop_unlock_desc, ufs_unlock },               /* unlock */
                   1286:        { &vop_bmap_desc, ext2fs_bmap },                /* bmap */
                   1287:        { &vop_strategy_desc, ufs_strategy },   /* strategy */
                   1288:        { &vop_print_desc, ufs_print },                 /* print */
                   1289:        { &vop_islocked_desc, ufs_islocked },   /* islocked */
                   1290:        { &vop_pathconf_desc, ufs_pathconf },   /* pathconf */
                   1291:        { &vop_advlock_desc, ext2fs_advlock },  /* advlock */
                   1292:        { &vop_bwrite_desc, vop_generic_bwrite },               /* bwrite */
                   1293:        { NULL, NULL }
                   1294: };
                   1295: struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
                   1296:        { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries };
                   1297:
                   1298: int (**ext2fs_specop_p)(void *);
                   1299: struct vnodeopv_entry_desc ext2fs_specop_entries[] = {
                   1300:        { &vop_default_desc, spec_vnoperate },
                   1301:        { &vop_close_desc, ufsspec_close },             /* close */
                   1302:        { &vop_access_desc, ext2fs_access },    /* access */
                   1303:        { &vop_getattr_desc, ext2fs_getattr },  /* getattr */
                   1304:        { &vop_setattr_desc, ext2fs_setattr },  /* setattr */
                   1305:        { &vop_read_desc, ufsspec_read },               /* read */
                   1306:        { &vop_write_desc, ufsspec_write },             /* write */
                   1307:        { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
                   1308:        { &vop_inactive_desc, ext2fs_inactive },/* inactive */
                   1309:        { &vop_reclaim_desc, ext2fs_reclaim },  /* reclaim */
                   1310:        { &vop_lock_desc, ufs_lock },                   /* lock */
                   1311:        { &vop_unlock_desc, ufs_unlock },               /* unlock */
                   1312:        { &vop_print_desc, ufs_print },                 /* print */
                   1313:        { &vop_islocked_desc, ufs_islocked },   /* islocked */
                   1314:        { NULL, NULL }
                   1315: };
                   1316: struct vnodeopv_desc ext2fs_specop_opv_desc =
                   1317:        { &ext2fs_specop_p, ext2fs_specop_entries };
                   1318:
                   1319: #ifdef FIFO
                   1320: int (**ext2fs_fifoop_p)(void *);
                   1321: struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = {
                   1322:        { &vop_default_desc, fifo_vnoperate },
                   1323:        { &vop_close_desc, ufsfifo_close },             /* close */
                   1324:        { &vop_access_desc, ext2fs_access },    /* access */
                   1325:        { &vop_getattr_desc, ext2fs_getattr },  /* getattr */
                   1326:        { &vop_setattr_desc, ext2fs_setattr },  /* setattr */
                   1327:        { &vop_read_desc, ufsfifo_read },               /* read */
                   1328:        { &vop_write_desc, ufsfifo_write },             /* write */
                   1329:        { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
                   1330:        { &vop_inactive_desc, ext2fs_inactive },/* inactive */
                   1331:        { &vop_reclaim_desc, ext2fsfifo_reclaim },      /* reclaim */
                   1332:        { &vop_lock_desc, ufs_lock },                   /* lock */
                   1333:        { &vop_unlock_desc, ufs_unlock },               /* unlock */
                   1334:        { &vop_print_desc, ufs_print },                 /* print */
                   1335:        { &vop_islocked_desc, ufs_islocked },   /* islocked */
                   1336:        { &vop_bwrite_desc, vop_generic_bwrite },               /* bwrite */
                   1337:        { NULL, NULL }
                   1338: };
                   1339: struct vnodeopv_desc ext2fs_fifoop_opv_desc =
                   1340:        { &ext2fs_fifoop_p, ext2fs_fifoop_entries };
                   1341:
                   1342: int
                   1343: ext2fsfifo_reclaim(void *v)
                   1344: {
                   1345:        fifo_reclaim(v);
                   1346:        return (ext2fs_reclaim(v));
                   1347: }
                   1348: #endif /* FIFO */

CVSweb