[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     ! 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