1*07feb63cScsapuntz /* $OpenBSD: ext2fs_vnops.c,v 1.6 1997/11/06 05:59:16 csapuntz Exp $ */ 21f3ff51cSdownsj /* $NetBSD: ext2fs_vnops.c,v 1.1 1997/06/11 09:34:09 bouyer Exp $ */ 35ac2d602Sdownsj 45ac2d602Sdownsj /* 51f3ff51cSdownsj * Copyright (c) 1997 Manuel Bouyer. 65ac2d602Sdownsj * Copyright (c) 1982, 1986, 1989, 1993 75ac2d602Sdownsj * The Regents of the University of California. All rights reserved. 85ac2d602Sdownsj * (c) UNIX System Laboratories, Inc. 95ac2d602Sdownsj * All or some portions of this file are derived from material licensed 105ac2d602Sdownsj * to the University of California by American Telephone and Telegraph 115ac2d602Sdownsj * Co. or Unix System Laboratories, Inc. and are reproduced herein with 125ac2d602Sdownsj * the permission of UNIX System Laboratories, Inc. 135ac2d602Sdownsj * 145ac2d602Sdownsj * Redistribution and use in source and binary forms, with or without 155ac2d602Sdownsj * modification, are permitted provided that the following conditions 165ac2d602Sdownsj * are met: 175ac2d602Sdownsj * 1. Redistributions of source code must retain the above copyright 185ac2d602Sdownsj * notice, this list of conditions and the following disclaimer. 195ac2d602Sdownsj * 2. Redistributions in binary form must reproduce the above copyright 205ac2d602Sdownsj * notice, this list of conditions and the following disclaimer in the 215ac2d602Sdownsj * documentation and/or other materials provided with the distribution. 225ac2d602Sdownsj * 3. All advertising materials mentioning features or use of this software 235ac2d602Sdownsj * must display the following acknowledgement: 245ac2d602Sdownsj * This product includes software developed by the University of 255ac2d602Sdownsj * California, Berkeley and its contributors. 265ac2d602Sdownsj * 4. Neither the name of the University nor the names of its contributors 275ac2d602Sdownsj * may be used to endorse or promote products derived from this software 285ac2d602Sdownsj * without specific prior written permission. 295ac2d602Sdownsj * 305ac2d602Sdownsj * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 315ac2d602Sdownsj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 325ac2d602Sdownsj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 335ac2d602Sdownsj * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 345ac2d602Sdownsj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 355ac2d602Sdownsj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 365ac2d602Sdownsj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 375ac2d602Sdownsj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 385ac2d602Sdownsj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 395ac2d602Sdownsj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 405ac2d602Sdownsj * SUCH DAMAGE. 415ac2d602Sdownsj * 425ac2d602Sdownsj * @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94 431f3ff51cSdownsj * Modified for ext2fs by Manuel Bouyer. 445ac2d602Sdownsj */ 455ac2d602Sdownsj 465ac2d602Sdownsj #include <sys/param.h> 475ac2d602Sdownsj #include <sys/systm.h> 485ac2d602Sdownsj #include <sys/resourcevar.h> 495ac2d602Sdownsj #include <sys/kernel.h> 505ac2d602Sdownsj #include <sys/file.h> 515ac2d602Sdownsj #include <sys/stat.h> 525ac2d602Sdownsj #include <sys/buf.h> 535ac2d602Sdownsj #include <sys/proc.h> 545ac2d602Sdownsj #include <sys/conf.h> 555ac2d602Sdownsj #include <sys/mount.h> 565ac2d602Sdownsj #include <sys/namei.h> 575ac2d602Sdownsj #include <sys/vnode.h> 585ac2d602Sdownsj #include <sys/lockf.h> 595ac2d602Sdownsj #include <sys/malloc.h> 605ac2d602Sdownsj #include <sys/signalvar.h> 615ac2d602Sdownsj 625ac2d602Sdownsj #include <vm/vm.h> 635ac2d602Sdownsj 645ac2d602Sdownsj #include <miscfs/fifofs/fifo.h> 655ac2d602Sdownsj #include <miscfs/specfs/specdev.h> 665ac2d602Sdownsj 675ac2d602Sdownsj #include <ufs/ufs/quota.h> 685ac2d602Sdownsj #include <ufs/ufs/inode.h> 695ac2d602Sdownsj #include <ufs/ufs/ufs_extern.h> 705ac2d602Sdownsj #include <ufs/ufs/ufsmount.h> 715ac2d602Sdownsj 725ac2d602Sdownsj #include <ufs/ext2fs/ext2fs.h> 735ac2d602Sdownsj #include <ufs/ext2fs/ext2fs_extern.h> 745ac2d602Sdownsj #include <ufs/ext2fs/ext2fs_dir.h> 755ac2d602Sdownsj 765ac2d602Sdownsj 775ac2d602Sdownsj static int ext2fs_chmod 785ac2d602Sdownsj __P((struct vnode *, int, struct ucred *, struct proc *)); 795ac2d602Sdownsj static int ext2fs_chown 805ac2d602Sdownsj __P((struct vnode *, uid_t, gid_t, struct ucred *, struct proc *)); 815ac2d602Sdownsj 825ac2d602Sdownsj union _qcvt { 835ac2d602Sdownsj int64_t qcvt; 845ac2d602Sdownsj int32_t val[2]; 855ac2d602Sdownsj }; 865ac2d602Sdownsj #define SETHIGH(q, h) { \ 875ac2d602Sdownsj union _qcvt tmp; \ 885ac2d602Sdownsj tmp.qcvt = (q); \ 895ac2d602Sdownsj tmp.val[_QUAD_HIGHWORD] = (h); \ 905ac2d602Sdownsj (q) = tmp.qcvt; \ 915ac2d602Sdownsj } 925ac2d602Sdownsj #define SETLOW(q, l) { \ 935ac2d602Sdownsj union _qcvt tmp; \ 945ac2d602Sdownsj tmp.qcvt = (q); \ 955ac2d602Sdownsj tmp.val[_QUAD_LOWWORD] = (l); \ 965ac2d602Sdownsj (q) = tmp.qcvt; \ 975ac2d602Sdownsj } 985ac2d602Sdownsj 995ac2d602Sdownsj /* 1005ac2d602Sdownsj * Create a regular file 1015ac2d602Sdownsj */ 1025ac2d602Sdownsj int 1035ac2d602Sdownsj ext2fs_create(v) 1045ac2d602Sdownsj void *v; 1055ac2d602Sdownsj { 1065ac2d602Sdownsj struct vop_create_args /* { 1075ac2d602Sdownsj struct vnode *a_dvp; 1085ac2d602Sdownsj struct vnode **a_vpp; 1095ac2d602Sdownsj struct componentname *a_cnp; 1105ac2d602Sdownsj struct vattr *a_vap; 1115ac2d602Sdownsj } */ *ap = v; 1125ac2d602Sdownsj return 1135ac2d602Sdownsj ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode), 1145ac2d602Sdownsj ap->a_dvp, ap->a_vpp, ap->a_cnp); 1155ac2d602Sdownsj } 1165ac2d602Sdownsj 1175ac2d602Sdownsj /* 1185ac2d602Sdownsj * Mknod vnode call 1195ac2d602Sdownsj */ 1205ac2d602Sdownsj /* ARGSUSED */ 1215ac2d602Sdownsj int 1225ac2d602Sdownsj ext2fs_mknod(v) 1235ac2d602Sdownsj void *v; 1245ac2d602Sdownsj { 1255ac2d602Sdownsj struct vop_mknod_args /* { 1265ac2d602Sdownsj struct vnode *a_dvp; 1275ac2d602Sdownsj struct vnode **a_vpp; 1285ac2d602Sdownsj struct componentname *a_cnp; 1295ac2d602Sdownsj struct vattr *a_vap; 1305ac2d602Sdownsj } */ *ap = v; 1315ac2d602Sdownsj register struct vattr *vap = ap->a_vap; 1325ac2d602Sdownsj register struct vnode **vpp = ap->a_vpp; 1335ac2d602Sdownsj register struct inode *ip; 1345ac2d602Sdownsj int error; 1355ac2d602Sdownsj 1365ac2d602Sdownsj if ((error = 1375ac2d602Sdownsj ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), 1385ac2d602Sdownsj ap->a_dvp, vpp, ap->a_cnp)) != 0) 1395ac2d602Sdownsj return (error); 1405ac2d602Sdownsj ip = VTOI(*vpp); 1415ac2d602Sdownsj ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 1425ac2d602Sdownsj if (vap->va_rdev != VNOVAL) { 1435ac2d602Sdownsj /* 1445ac2d602Sdownsj * Want to be able to use this to make badblock 1455ac2d602Sdownsj * inodes, so don't truncate the dev number. 1465ac2d602Sdownsj */ 1475ac2d602Sdownsj ip->i_din.e2fs_din.e2di_rdev = vap->va_rdev; 1485ac2d602Sdownsj } 1495ac2d602Sdownsj /* 1505ac2d602Sdownsj * Remove inode so that it will be reloaded by VFS_VGET and 1515ac2d602Sdownsj * checked to see if it is an alias of an existing entry in 1525ac2d602Sdownsj * the inode cache. 1535ac2d602Sdownsj */ 1545ac2d602Sdownsj vput(*vpp); 1555ac2d602Sdownsj (*vpp)->v_type = VNON; 1565ac2d602Sdownsj vgone(*vpp); 1575ac2d602Sdownsj *vpp = 0; 1585ac2d602Sdownsj return (0); 1595ac2d602Sdownsj } 1605ac2d602Sdownsj 1615ac2d602Sdownsj /* 1625ac2d602Sdownsj * Open called. 1635ac2d602Sdownsj * 1645ac2d602Sdownsj * Just check the APPEND flag. 1655ac2d602Sdownsj */ 1665ac2d602Sdownsj /* ARGSUSED */ 1675ac2d602Sdownsj int 1685ac2d602Sdownsj ext2fs_open(v) 1695ac2d602Sdownsj void *v; 1705ac2d602Sdownsj { 1715ac2d602Sdownsj struct vop_open_args /* { 1725ac2d602Sdownsj struct vnode *a_vp; 1735ac2d602Sdownsj int a_mode; 1745ac2d602Sdownsj struct ucred *a_cred; 1755ac2d602Sdownsj struct proc *a_p; 1765ac2d602Sdownsj } */ *ap = v; 1775ac2d602Sdownsj 1785ac2d602Sdownsj /* 1795ac2d602Sdownsj * Files marked append-only must be opened for appending. 1805ac2d602Sdownsj */ 1815ac2d602Sdownsj if ((VTOI(ap->a_vp)->i_e2fs_flags & EXT2_APPEND) && 1825ac2d602Sdownsj (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) 1835ac2d602Sdownsj return (EPERM); 1845ac2d602Sdownsj return (0); 1855ac2d602Sdownsj } 1865ac2d602Sdownsj 1875ac2d602Sdownsj int 1885ac2d602Sdownsj ext2fs_access(v) 1895ac2d602Sdownsj void *v; 1905ac2d602Sdownsj { 1915ac2d602Sdownsj struct vop_access_args /* { 1925ac2d602Sdownsj struct vnode *a_vp; 1935ac2d602Sdownsj int a_mode; 1945ac2d602Sdownsj struct ucred *a_cred; 1955ac2d602Sdownsj struct proc *a_p; 1965ac2d602Sdownsj } */ *ap = v; 1975ac2d602Sdownsj register struct vnode *vp = ap->a_vp; 1985ac2d602Sdownsj register struct inode *ip = VTOI(vp); 1995ac2d602Sdownsj mode_t mode = ap->a_mode; 2005ac2d602Sdownsj 2015ac2d602Sdownsj #ifdef DIAGNOSTIC 2025ac2d602Sdownsj if (!VOP_ISLOCKED(vp)) { 2035ac2d602Sdownsj vprint("ext2fs_access: not locked", vp); 2045ac2d602Sdownsj panic("ext2fs_access: not locked"); 2055ac2d602Sdownsj } 2065ac2d602Sdownsj #endif 2075ac2d602Sdownsj 2085ac2d602Sdownsj /* If immutable bit set, nobody gets to write it. */ 2095ac2d602Sdownsj if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE)) 2105ac2d602Sdownsj return (EPERM); 2115ac2d602Sdownsj 2125ed759e3Sdownsj return (vaccess(ip->i_e2fs_mode, ip->i_e2fs_uid, ip->i_e2fs_gid, mode, 2135ac2d602Sdownsj ap->a_cred)); 2145ac2d602Sdownsj } 2155ac2d602Sdownsj 2165ac2d602Sdownsj /* ARGSUSED */ 2175ac2d602Sdownsj int 2185ac2d602Sdownsj ext2fs_getattr(v) 2195ac2d602Sdownsj void *v; 2205ac2d602Sdownsj { 2215ac2d602Sdownsj struct vop_getattr_args /* { 2225ac2d602Sdownsj struct vnode *a_vp; 2235ac2d602Sdownsj struct vattr *a_vap; 2245ac2d602Sdownsj struct ucred *a_cred; 2255ac2d602Sdownsj struct proc *a_p; 2265ac2d602Sdownsj } */ *ap = v; 2275ac2d602Sdownsj register struct vnode *vp = ap->a_vp; 2285ac2d602Sdownsj register struct inode *ip = VTOI(vp); 2295ac2d602Sdownsj register struct vattr *vap = ap->a_vap; 2305ac2d602Sdownsj 2317dc61945Sdownsj EXT2FS_ITIMES(ip, &time, &time); 2325ac2d602Sdownsj /* 2335ac2d602Sdownsj * Copy from inode table 2345ac2d602Sdownsj */ 2355ac2d602Sdownsj vap->va_fsid = ip->i_dev; 2365ac2d602Sdownsj vap->va_fileid = ip->i_number; 2371f3ff51cSdownsj vap->va_mode = ip->i_e2fs_mode & ALLPERMS; 2385ac2d602Sdownsj vap->va_nlink = ip->i_e2fs_nlink; 2395ac2d602Sdownsj vap->va_uid = ip->i_e2fs_uid; 2405ac2d602Sdownsj vap->va_gid = ip->i_e2fs_gid; 2415ac2d602Sdownsj vap->va_rdev = (dev_t)ip->i_din.e2fs_din.e2di_rdev; 2425ac2d602Sdownsj vap->va_size = ip->i_e2fs_size; 2435ac2d602Sdownsj vap->va_atime.tv_sec = ip->i_e2fs_atime; 2445ac2d602Sdownsj vap->va_atime.tv_nsec = 0; 2455ac2d602Sdownsj vap->va_mtime.tv_sec = ip->i_e2fs_mtime; 2465ac2d602Sdownsj vap->va_mtime.tv_nsec = 0; 2475ac2d602Sdownsj vap->va_ctime.tv_sec = ip->i_e2fs_ctime; 2485ac2d602Sdownsj vap->va_ctime.tv_nsec = 0; 2495ac2d602Sdownsj #ifdef EXT2FS_SYSTEM_FLAGS 2505ac2d602Sdownsj vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0; 2515ac2d602Sdownsj vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0; 2525ac2d602Sdownsj #else 2535ac2d602Sdownsj vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? UF_APPEND : 0; 2545ac2d602Sdownsj vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? UF_IMMUTABLE : 0; 2555ac2d602Sdownsj #endif 2565ac2d602Sdownsj vap->va_gen = ip->i_e2fs_gen; 2575ac2d602Sdownsj /* this doesn't belong here */ 2585ac2d602Sdownsj if (vp->v_type == VBLK) 2595ac2d602Sdownsj vap->va_blocksize = BLKDEV_IOSIZE; 2605ac2d602Sdownsj else if (vp->v_type == VCHR) 2615ac2d602Sdownsj vap->va_blocksize = MAXBSIZE; 2625ac2d602Sdownsj else 2635ac2d602Sdownsj vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; 2645ac2d602Sdownsj vap->va_bytes = dbtob(ip->i_e2fs_nblock); 2655ac2d602Sdownsj vap->va_type = vp->v_type; 2665ac2d602Sdownsj vap->va_filerev = ip->i_modrev; 2675ac2d602Sdownsj return (0); 2685ac2d602Sdownsj } 2695ac2d602Sdownsj 2705ac2d602Sdownsj /* 2715ac2d602Sdownsj * Set attribute vnode op. called from several syscalls 2725ac2d602Sdownsj */ 2735ac2d602Sdownsj int 2745ac2d602Sdownsj ext2fs_setattr(v) 2755ac2d602Sdownsj void *v; 2765ac2d602Sdownsj { 2775ac2d602Sdownsj struct vop_setattr_args /* { 2785ac2d602Sdownsj struct vnode *a_vp; 2795ac2d602Sdownsj struct vattr *a_vap; 2805ac2d602Sdownsj struct ucred *a_cred; 2815ac2d602Sdownsj struct proc *a_p; 2825ac2d602Sdownsj } */ *ap = v; 2835ac2d602Sdownsj register struct vattr *vap = ap->a_vap; 2845ac2d602Sdownsj register struct vnode *vp = ap->a_vp; 2855ac2d602Sdownsj register struct inode *ip = VTOI(vp); 2865ac2d602Sdownsj register struct ucred *cred = ap->a_cred; 2875ac2d602Sdownsj register struct proc *p = ap->a_p; 2885ac2d602Sdownsj int error; 2895ac2d602Sdownsj 2905ac2d602Sdownsj /* 2915ac2d602Sdownsj * Check for unsettable attributes. 2925ac2d602Sdownsj */ 2935ac2d602Sdownsj if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 2945ac2d602Sdownsj (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 2955ac2d602Sdownsj (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 2965ac2d602Sdownsj ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 2975ac2d602Sdownsj return (EINVAL); 2985ac2d602Sdownsj } 2995ac2d602Sdownsj if (vap->va_flags != VNOVAL) { 3005ac2d602Sdownsj if (cred->cr_uid != ip->i_e2fs_uid && 3015ac2d602Sdownsj (error = suser(cred, &p->p_acflag))) 3025ac2d602Sdownsj return (error); 3035ac2d602Sdownsj #ifdef EXT2FS_SYSTEM_FLAGS 3045ac2d602Sdownsj if (cred->cr_uid == 0) { 3055ac2d602Sdownsj if ((ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE)) && 3065ac2d602Sdownsj securelevel > 0) 3075ac2d602Sdownsj return (EPERM); 3085ac2d602Sdownsj ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE); 3095ac2d602Sdownsj ip->i_e2fs_flags |= (vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 | 3105ac2d602Sdownsj (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0; 3115ac2d602Sdownsj } else { 3125ac2d602Sdownsj return (EPERM); 3135ac2d602Sdownsj } 3145ac2d602Sdownsj #else 3155ac2d602Sdownsj ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE); 3165ac2d602Sdownsj ip->i_e2fs_flags |= (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 | 3175ac2d602Sdownsj (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE: 0; 3185ac2d602Sdownsj #endif 3195ac2d602Sdownsj ip->i_flag |= IN_CHANGE; 3205ac2d602Sdownsj if (vap->va_flags & (IMMUTABLE | APPEND)) 3215ac2d602Sdownsj return (0); 3225ac2d602Sdownsj } 3235ac2d602Sdownsj if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE)) 3245ac2d602Sdownsj return (EPERM); 3255ac2d602Sdownsj /* 3265ac2d602Sdownsj * Go through the fields and update iff not VNOVAL. 3275ac2d602Sdownsj */ 3285ac2d602Sdownsj if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 3295ac2d602Sdownsj error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, p); 3305ac2d602Sdownsj if (error) 3315ac2d602Sdownsj return (error); 3325ac2d602Sdownsj } 3335ac2d602Sdownsj if (vap->va_size != VNOVAL) { 3345ac2d602Sdownsj if (vp->v_type == VDIR) 3355ac2d602Sdownsj return (EISDIR); 3365ac2d602Sdownsj error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p); 3375ac2d602Sdownsj if (error) 3385ac2d602Sdownsj return (error); 3395ac2d602Sdownsj } 3405ac2d602Sdownsj ip = VTOI(vp); 3415ac2d602Sdownsj if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 3425ac2d602Sdownsj if (cred->cr_uid != ip->i_e2fs_uid && 3435ac2d602Sdownsj (error = suser(cred, &p->p_acflag)) && 3445ac2d602Sdownsj ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 3455ac2d602Sdownsj (error = VOP_ACCESS(vp, VWRITE, cred, p)))) 3465ac2d602Sdownsj return (error); 3475ac2d602Sdownsj if (vap->va_atime.tv_sec != VNOVAL) 3485ac2d602Sdownsj if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) 3495ac2d602Sdownsj ip->i_flag |= IN_ACCESS; 3505ac2d602Sdownsj if (vap->va_mtime.tv_sec != VNOVAL) 3515ac2d602Sdownsj ip->i_flag |= IN_CHANGE | IN_UPDATE; 3525ac2d602Sdownsj error = VOP_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 1); 3535ac2d602Sdownsj if (error) 3545ac2d602Sdownsj return (error); 3555ac2d602Sdownsj } 3565ac2d602Sdownsj error = 0; 3575ac2d602Sdownsj if (vap->va_mode != (mode_t)VNOVAL) 3585ac2d602Sdownsj error = ext2fs_chmod(vp, (int)vap->va_mode, cred, p); 3595ac2d602Sdownsj return (error); 3605ac2d602Sdownsj } 3615ac2d602Sdownsj 3625ac2d602Sdownsj /* 3635ac2d602Sdownsj * Change the mode on a file. 3645ac2d602Sdownsj * Inode must be locked before calling. 3655ac2d602Sdownsj */ 3665ac2d602Sdownsj static int 3675ac2d602Sdownsj ext2fs_chmod(vp, mode, cred, p) 3685ac2d602Sdownsj register struct vnode *vp; 3695ac2d602Sdownsj register int mode; 3705ac2d602Sdownsj register struct ucred *cred; 3715ac2d602Sdownsj struct proc *p; 3725ac2d602Sdownsj { 3735ac2d602Sdownsj register struct inode *ip = VTOI(vp); 3745ac2d602Sdownsj int error; 3755ac2d602Sdownsj 3765ac2d602Sdownsj if (cred->cr_uid != ip->i_e2fs_uid && 3775ac2d602Sdownsj (error = suser(cred, &p->p_acflag))) 3785ac2d602Sdownsj return (error); 3795ac2d602Sdownsj if (cred->cr_uid) { 3805ac2d602Sdownsj if (vp->v_type != VDIR && (mode & S_ISTXT)) 3815ac2d602Sdownsj return (EFTYPE); 3825ac2d602Sdownsj if (!groupmember(ip->i_e2fs_gid, cred) && (mode & ISGID)) 3835ac2d602Sdownsj return (EPERM); 3845ac2d602Sdownsj } 3855ac2d602Sdownsj ip->i_e2fs_mode &= ~ALLPERMS; 3865ac2d602Sdownsj ip->i_e2fs_mode |= (mode & ALLPERMS); 3875ac2d602Sdownsj ip->i_flag |= IN_CHANGE; 3885ac2d602Sdownsj if ((vp->v_flag & VTEXT) && (ip->i_e2fs_mode & S_ISTXT) == 0) 3895ac2d602Sdownsj (void) vnode_pager_uncache(vp); 3905ac2d602Sdownsj return (0); 3915ac2d602Sdownsj } 3925ac2d602Sdownsj 3935ac2d602Sdownsj /* 3945ac2d602Sdownsj * Perform chown operation on inode ip; 3955ac2d602Sdownsj * inode must be locked prior to call. 3965ac2d602Sdownsj */ 3975ac2d602Sdownsj static int 3985ac2d602Sdownsj ext2fs_chown(vp, uid, gid, cred, p) 3995ac2d602Sdownsj register struct vnode *vp; 4005ac2d602Sdownsj uid_t uid; 4015ac2d602Sdownsj gid_t gid; 4025ac2d602Sdownsj struct ucred *cred; 4035ac2d602Sdownsj struct proc *p; 4045ac2d602Sdownsj { 4055ac2d602Sdownsj register struct inode *ip = VTOI(vp); 4065ac2d602Sdownsj uid_t ouid; 4075ac2d602Sdownsj gid_t ogid; 4085ac2d602Sdownsj int error = 0; 4095ac2d602Sdownsj 4105ac2d602Sdownsj if (uid == (uid_t)VNOVAL) 4115ac2d602Sdownsj uid = ip->i_e2fs_uid; 4125ac2d602Sdownsj if (gid == (gid_t)VNOVAL) 4135ac2d602Sdownsj gid = ip->i_e2fs_gid; 4145ac2d602Sdownsj /* 4155ac2d602Sdownsj * If we don't own the file, are trying to change the owner 4165ac2d602Sdownsj * of the file, or are not a member of the target group, 4175ac2d602Sdownsj * the caller must be superuser or the call fails. 4185ac2d602Sdownsj */ 4195ac2d602Sdownsj if ((cred->cr_uid != ip->i_e2fs_uid || uid != ip->i_e2fs_uid || 4205ac2d602Sdownsj (gid != ip->i_e2fs_gid && !groupmember((gid_t)gid, cred))) && 4215ac2d602Sdownsj (error = suser(cred, &p->p_acflag))) 4225ac2d602Sdownsj return (error); 4235ac2d602Sdownsj ogid = ip->i_e2fs_gid; 4245ac2d602Sdownsj ouid = ip->i_e2fs_uid; 4255ac2d602Sdownsj 4265ac2d602Sdownsj ip->i_e2fs_gid = gid; 4275ac2d602Sdownsj ip->i_e2fs_uid = uid; 4285ac2d602Sdownsj if (ouid != uid || ogid != gid) 4295ac2d602Sdownsj ip->i_flag |= IN_CHANGE; 4305ac2d602Sdownsj if (ouid != uid && cred->cr_uid != 0) 4315ac2d602Sdownsj ip->i_e2fs_mode &= ~ISUID; 4325ac2d602Sdownsj if (ogid != gid && cred->cr_uid != 0) 4335ac2d602Sdownsj ip->i_e2fs_mode &= ~ISGID; 4345ac2d602Sdownsj return (0); 4355ac2d602Sdownsj } 4365ac2d602Sdownsj 4375ac2d602Sdownsj int 4385ac2d602Sdownsj ext2fs_remove(v) 4395ac2d602Sdownsj void *v; 4405ac2d602Sdownsj { 4415ac2d602Sdownsj struct vop_remove_args /* { 4425ac2d602Sdownsj struct vnode *a_dvp; 4435ac2d602Sdownsj struct vnode *a_vp; 4445ac2d602Sdownsj struct componentname *a_cnp; 4455ac2d602Sdownsj } */ *ap = v; 4465ac2d602Sdownsj register struct inode *ip; 4475ac2d602Sdownsj register struct vnode *vp = ap->a_vp; 4485ac2d602Sdownsj register struct vnode *dvp = ap->a_dvp; 4495ac2d602Sdownsj int error; 4505ac2d602Sdownsj 4515ac2d602Sdownsj ip = VTOI(vp); 452d56d3b9eSderaadt if (vp->v_type == VDIR || 453d56d3b9eSderaadt (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) || 4545ac2d602Sdownsj (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) { 4555ac2d602Sdownsj error = EPERM; 4565ac2d602Sdownsj goto out; 4575ac2d602Sdownsj } 4585ac2d602Sdownsj error = ext2fs_dirremove(dvp, ap->a_cnp); 4595ac2d602Sdownsj if (error == 0) { 4605ac2d602Sdownsj ip->i_e2fs_nlink--; 4615ac2d602Sdownsj ip->i_flag |= IN_CHANGE; 4625ac2d602Sdownsj } 4635ac2d602Sdownsj out: 4645ac2d602Sdownsj if (dvp == vp) 4655ac2d602Sdownsj vrele(vp); 4665ac2d602Sdownsj else 4675ac2d602Sdownsj vput(vp); 4685ac2d602Sdownsj vput(dvp); 4695ac2d602Sdownsj return (error); 4705ac2d602Sdownsj } 4715ac2d602Sdownsj 4725ac2d602Sdownsj /* 4735ac2d602Sdownsj * link vnode call 4745ac2d602Sdownsj */ 4755ac2d602Sdownsj int 4765ac2d602Sdownsj ext2fs_link(v) 4775ac2d602Sdownsj void *v; 4785ac2d602Sdownsj { 4795ac2d602Sdownsj struct vop_link_args /* { 4805ac2d602Sdownsj struct vnode *a_dvp; 4815ac2d602Sdownsj struct vnode *a_vp; 4825ac2d602Sdownsj struct componentname *a_cnp; 4835ac2d602Sdownsj } */ *ap = v; 4845ac2d602Sdownsj register struct vnode *dvp = ap->a_dvp; 4855ac2d602Sdownsj register struct vnode *vp = ap->a_vp; 4865ac2d602Sdownsj register struct componentname *cnp = ap->a_cnp; 487*07feb63cScsapuntz struct proc *p = cnp->cn_proc; 4885ac2d602Sdownsj register struct inode *ip; 4895ac2d602Sdownsj struct timespec ts; 4905ac2d602Sdownsj int error; 4915ac2d602Sdownsj 4925ac2d602Sdownsj #ifdef DIAGNOSTIC 4935ac2d602Sdownsj if ((cnp->cn_flags & HASBUF) == 0) 4945ac2d602Sdownsj panic("ext2fs_link: no name"); 4955ac2d602Sdownsj #endif 4965ac2d602Sdownsj if (vp->v_type == VDIR) { 4975ac2d602Sdownsj VOP_ABORTOP(dvp, cnp); 4985ac2d602Sdownsj error = EISDIR; 4995ac2d602Sdownsj goto out2; 5005ac2d602Sdownsj } 5015ac2d602Sdownsj if (dvp->v_mount != vp->v_mount) { 5025ac2d602Sdownsj VOP_ABORTOP(dvp, cnp); 5035ac2d602Sdownsj error = EXDEV; 5045ac2d602Sdownsj goto out2; 5055ac2d602Sdownsj } 506*07feb63cScsapuntz if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p))) { 5075ac2d602Sdownsj VOP_ABORTOP(dvp, cnp); 5085ac2d602Sdownsj goto out2; 5095ac2d602Sdownsj } 5105ac2d602Sdownsj ip = VTOI(vp); 5115ac2d602Sdownsj if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) { 5125ac2d602Sdownsj VOP_ABORTOP(dvp, cnp); 5135ac2d602Sdownsj error = EMLINK; 5145ac2d602Sdownsj goto out1; 5155ac2d602Sdownsj } 5165ac2d602Sdownsj if (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) { 5175ac2d602Sdownsj VOP_ABORTOP(dvp, cnp); 5185ac2d602Sdownsj error = EPERM; 5195ac2d602Sdownsj goto out1; 5205ac2d602Sdownsj } 5215ac2d602Sdownsj ip->i_e2fs_nlink++; 5225ac2d602Sdownsj ip->i_flag |= IN_CHANGE; 5235ac2d602Sdownsj TIMEVAL_TO_TIMESPEC(&time, &ts); 5245ac2d602Sdownsj error = VOP_UPDATE(vp, &ts, &ts, 1); 5255ac2d602Sdownsj if (!error) 5265ac2d602Sdownsj error = ext2fs_direnter(ip, dvp, cnp); 5275ac2d602Sdownsj if (error) { 5285ac2d602Sdownsj ip->i_e2fs_nlink--; 5295ac2d602Sdownsj ip->i_flag |= IN_CHANGE; 5305ac2d602Sdownsj } 5315ac2d602Sdownsj FREE(cnp->cn_pnbuf, M_NAMEI); 5325ac2d602Sdownsj out1: 5335ac2d602Sdownsj if (dvp != vp) 534*07feb63cScsapuntz VOP_UNLOCK(vp, 0, p); 5355ac2d602Sdownsj out2: 5365ac2d602Sdownsj vput(dvp); 5375ac2d602Sdownsj return (error); 5385ac2d602Sdownsj } 5395ac2d602Sdownsj 5405ac2d602Sdownsj /* 5415ac2d602Sdownsj * Rename system call. 5425ac2d602Sdownsj * rename("foo", "bar"); 5435ac2d602Sdownsj * is essentially 5445ac2d602Sdownsj * unlink("bar"); 5455ac2d602Sdownsj * link("foo", "bar"); 5465ac2d602Sdownsj * unlink("foo"); 5475ac2d602Sdownsj * but ``atomically''. Can't do full commit without saving state in the 5485ac2d602Sdownsj * inode on disk which isn't feasible at this time. Best we can do is 5495ac2d602Sdownsj * always guarantee the target exists. 5505ac2d602Sdownsj * 5515ac2d602Sdownsj * Basic algorithm is: 5525ac2d602Sdownsj * 5535ac2d602Sdownsj * 1) Bump link count on source while we're linking it to the 5545ac2d602Sdownsj * target. This also ensure the inode won't be deleted out 5555ac2d602Sdownsj * from underneath us while we work (it may be truncated by 5565ac2d602Sdownsj * a concurrent `trunc' or `open' for creation). 5575ac2d602Sdownsj * 2) Link source to destination. If destination already exists, 5585ac2d602Sdownsj * delete it first. 5595ac2d602Sdownsj * 3) Unlink source reference to inode if still around. If a 5605ac2d602Sdownsj * directory was moved and the parent of the destination 5615ac2d602Sdownsj * is different from the source, patch the ".." entry in the 5625ac2d602Sdownsj * directory. 5635ac2d602Sdownsj */ 5645ac2d602Sdownsj int 5655ac2d602Sdownsj ext2fs_rename(v) 5665ac2d602Sdownsj void *v; 5675ac2d602Sdownsj { 5685ac2d602Sdownsj struct vop_rename_args /* { 5695ac2d602Sdownsj struct vnode *a_fdvp; 5705ac2d602Sdownsj struct vnode *a_fvp; 5715ac2d602Sdownsj struct componentname *a_fcnp; 5725ac2d602Sdownsj struct vnode *a_tdvp; 5735ac2d602Sdownsj struct vnode *a_tvp; 5745ac2d602Sdownsj struct componentname *a_tcnp; 5755ac2d602Sdownsj } */ *ap = v; 5765ac2d602Sdownsj struct vnode *tvp = ap->a_tvp; 5775ac2d602Sdownsj register struct vnode *tdvp = ap->a_tdvp; 5785ac2d602Sdownsj struct vnode *fvp = ap->a_fvp; 5795ac2d602Sdownsj register struct vnode *fdvp = ap->a_fdvp; 5805ac2d602Sdownsj register struct componentname *tcnp = ap->a_tcnp; 5815ac2d602Sdownsj register struct componentname *fcnp = ap->a_fcnp; 5825ac2d602Sdownsj register struct inode *ip, *xp, *dp; 583*07feb63cScsapuntz struct proc *p = fcnp->cn_proc; 5845ac2d602Sdownsj struct ext2fs_dirtemplate dirbuf; 5855ac2d602Sdownsj struct timespec ts; 5865ac2d602Sdownsj int doingdirectory = 0, oldparent = 0, newparent = 0; 5875ac2d602Sdownsj int error = 0; 5885ac2d602Sdownsj u_char namlen; 5895ac2d602Sdownsj 5905ac2d602Sdownsj #ifdef DIAGNOSTIC 5915ac2d602Sdownsj if ((tcnp->cn_flags & HASBUF) == 0 || 5925ac2d602Sdownsj (fcnp->cn_flags & HASBUF) == 0) 5935ac2d602Sdownsj panic("ext2fs_rename: no name"); 5945ac2d602Sdownsj #endif 5955ac2d602Sdownsj /* 5965ac2d602Sdownsj * Check for cross-device rename. 5975ac2d602Sdownsj */ 5985ac2d602Sdownsj if ((fvp->v_mount != tdvp->v_mount) || 5995ac2d602Sdownsj (tvp && (fvp->v_mount != tvp->v_mount))) { 6005ac2d602Sdownsj error = EXDEV; 6015ac2d602Sdownsj abortit: 6025ac2d602Sdownsj VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */ 6035ac2d602Sdownsj if (tdvp == tvp) 6045ac2d602Sdownsj vrele(tdvp); 6055ac2d602Sdownsj else 6065ac2d602Sdownsj vput(tdvp); 6075ac2d602Sdownsj if (tvp) 6085ac2d602Sdownsj vput(tvp); 6095ac2d602Sdownsj VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */ 6105ac2d602Sdownsj vrele(fdvp); 6115ac2d602Sdownsj vrele(fvp); 6125ac2d602Sdownsj return (error); 6135ac2d602Sdownsj } 6145ac2d602Sdownsj 6155ac2d602Sdownsj /* 6165ac2d602Sdownsj * Check if just deleting a link name. 6175ac2d602Sdownsj */ 6185ac2d602Sdownsj if (tvp && ((VTOI(tvp)->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) || 6195ac2d602Sdownsj (VTOI(tdvp)->i_e2fs_flags & EXT2_APPEND))) { 6205ac2d602Sdownsj error = EPERM; 6215ac2d602Sdownsj goto abortit; 6225ac2d602Sdownsj } 6235ac2d602Sdownsj if (fvp == tvp) { 6245ac2d602Sdownsj if (fvp->v_type == VDIR) { 6255ac2d602Sdownsj error = EINVAL; 6265ac2d602Sdownsj goto abortit; 6275ac2d602Sdownsj } 6285ac2d602Sdownsj 6295ac2d602Sdownsj /* Release destination completely. */ 6305ac2d602Sdownsj VOP_ABORTOP(tdvp, tcnp); 6315ac2d602Sdownsj vput(tdvp); 6325ac2d602Sdownsj vput(tvp); 6335ac2d602Sdownsj 6345ac2d602Sdownsj /* Delete source. */ 6355ac2d602Sdownsj vrele(fdvp); 6365ac2d602Sdownsj vrele(fvp); 6375ac2d602Sdownsj fcnp->cn_flags &= ~MODMASK; 6385ac2d602Sdownsj fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; 6395ac2d602Sdownsj if ((fcnp->cn_flags & SAVESTART) == 0) 6405ac2d602Sdownsj panic("ext2fs_rename: lost from startdir"); 6415ac2d602Sdownsj fcnp->cn_nameiop = DELETE; 6425ac2d602Sdownsj (void) relookup(fdvp, &fvp, fcnp); 6435ac2d602Sdownsj return (VOP_REMOVE(fdvp, fvp, fcnp)); 6445ac2d602Sdownsj } 645*07feb63cScsapuntz if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p)) != 0) 6465ac2d602Sdownsj goto abortit; 6475ac2d602Sdownsj dp = VTOI(fdvp); 6485ac2d602Sdownsj ip = VTOI(fvp); 6495ac2d602Sdownsj if ((ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) || 6505ac2d602Sdownsj (dp->i_e2fs_flags & EXT2_APPEND)) { 651*07feb63cScsapuntz VOP_UNLOCK(fvp, 0, p); 6525ac2d602Sdownsj error = EPERM; 6535ac2d602Sdownsj goto abortit; 6545ac2d602Sdownsj } 6555ac2d602Sdownsj if ((ip->i_e2fs_mode & IFMT) == IFDIR) { 6565ac2d602Sdownsj error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc); 6575ac2d602Sdownsj if (!error && tvp) 6585ac2d602Sdownsj error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc); 6595ac2d602Sdownsj if (error) { 660*07feb63cScsapuntz VOP_UNLOCK(fvp, 0, p); 6615ac2d602Sdownsj error = EACCES; 6625ac2d602Sdownsj goto abortit; 6635ac2d602Sdownsj } 6645ac2d602Sdownsj /* 6655ac2d602Sdownsj * Avoid ".", "..", and aliases of "." for obvious reasons. 6665ac2d602Sdownsj */ 6675ac2d602Sdownsj if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || 668d56d3b9eSderaadt dp == ip || 669d56d3b9eSderaadt (fcnp->cn_flags&ISDOTDOT) || 670d56d3b9eSderaadt (tcnp->cn_flags & ISDOTDOT) || 6715ac2d602Sdownsj (ip->i_flag & IN_RENAME)) { 672*07feb63cScsapuntz VOP_UNLOCK(fvp, 0, p); 6735ac2d602Sdownsj error = EINVAL; 6745ac2d602Sdownsj goto abortit; 6755ac2d602Sdownsj } 6765ac2d602Sdownsj ip->i_flag |= IN_RENAME; 6775ac2d602Sdownsj oldparent = dp->i_number; 6785ac2d602Sdownsj doingdirectory++; 6795ac2d602Sdownsj } 6805ac2d602Sdownsj vrele(fdvp); 6815ac2d602Sdownsj 6825ac2d602Sdownsj /* 6835ac2d602Sdownsj * When the target exists, both the directory 6845ac2d602Sdownsj * and target vnodes are returned locked. 6855ac2d602Sdownsj */ 6865ac2d602Sdownsj dp = VTOI(tdvp); 6875ac2d602Sdownsj xp = NULL; 6885ac2d602Sdownsj if (tvp) 6895ac2d602Sdownsj xp = VTOI(tvp); 6905ac2d602Sdownsj 6915ac2d602Sdownsj /* 6925ac2d602Sdownsj * 1) Bump link count while we're moving stuff 6935ac2d602Sdownsj * around. If we crash somewhere before 6945ac2d602Sdownsj * completing our work, the link count 6955ac2d602Sdownsj * may be wrong, but correctable. 6965ac2d602Sdownsj */ 6975ac2d602Sdownsj ip->i_e2fs_nlink++; 6985ac2d602Sdownsj ip->i_flag |= IN_CHANGE; 6995ac2d602Sdownsj TIMEVAL_TO_TIMESPEC(&time, &ts); 7005ac2d602Sdownsj if ((error = VOP_UPDATE(fvp, &ts, &ts, 1)) != 0) { 701*07feb63cScsapuntz VOP_UNLOCK(fvp, 0, p); 7025ac2d602Sdownsj goto bad; 7035ac2d602Sdownsj } 7045ac2d602Sdownsj 7055ac2d602Sdownsj /* 7065ac2d602Sdownsj * If ".." must be changed (ie the directory gets a new 7075ac2d602Sdownsj * parent) then the source directory must not be in the 7085ac2d602Sdownsj * directory heirarchy above the target, as this would 7095ac2d602Sdownsj * orphan everything below the source directory. Also 7105ac2d602Sdownsj * the user must have write permission in the source so 7115ac2d602Sdownsj * as to be able to change "..". We must repeat the call 7125ac2d602Sdownsj * to namei, as the parent directory is unlocked by the 7135ac2d602Sdownsj * call to checkpath(). 7145ac2d602Sdownsj */ 7155ac2d602Sdownsj error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc); 716*07feb63cScsapuntz VOP_UNLOCK(fvp, 0, p); 7175ac2d602Sdownsj if (oldparent != dp->i_number) 7185ac2d602Sdownsj newparent = dp->i_number; 7195ac2d602Sdownsj if (doingdirectory && newparent) { 7205ac2d602Sdownsj if (error) /* write access check above */ 7215ac2d602Sdownsj goto bad; 7225ac2d602Sdownsj if (xp != NULL) 7235ac2d602Sdownsj vput(tvp); 7245ac2d602Sdownsj error = ext2fs_checkpath(ip, dp, tcnp->cn_cred); 7255ac2d602Sdownsj if (error != 0) 7265ac2d602Sdownsj goto out; 7275ac2d602Sdownsj if ((tcnp->cn_flags & SAVESTART) == 0) 7285ac2d602Sdownsj panic("ext2fs_rename: lost to startdir"); 7295ac2d602Sdownsj if ((error = relookup(tdvp, &tvp, tcnp)) != 0) 7305ac2d602Sdownsj goto out; 7315ac2d602Sdownsj dp = VTOI(tdvp); 7325ac2d602Sdownsj xp = NULL; 7335ac2d602Sdownsj if (tvp) 7345ac2d602Sdownsj xp = VTOI(tvp); 7355ac2d602Sdownsj } 7365ac2d602Sdownsj /* 7375ac2d602Sdownsj * 2) If target doesn't exist, link the target 7385ac2d602Sdownsj * to the source and unlink the source. 7395ac2d602Sdownsj * Otherwise, rewrite the target directory 7405ac2d602Sdownsj * entry to reference the source inode and 7415ac2d602Sdownsj * expunge the original entry's existence. 7425ac2d602Sdownsj */ 7435ac2d602Sdownsj if (xp == NULL) { 7445ac2d602Sdownsj if (dp->i_dev != ip->i_dev) 7455ac2d602Sdownsj panic("rename: EXDEV"); 7465ac2d602Sdownsj /* 7475ac2d602Sdownsj * Account for ".." in new directory. 7485ac2d602Sdownsj * When source and destination have the same 7495ac2d602Sdownsj * parent we don't fool with the link count. 7505ac2d602Sdownsj */ 7515ac2d602Sdownsj if (doingdirectory && newparent) { 7525ac2d602Sdownsj if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) { 7535ac2d602Sdownsj error = EMLINK; 7545ac2d602Sdownsj goto bad; 7555ac2d602Sdownsj } 7565ac2d602Sdownsj dp->i_e2fs_nlink++; 7575ac2d602Sdownsj dp->i_flag |= IN_CHANGE; 7585ac2d602Sdownsj if ((error = VOP_UPDATE(tdvp, &ts, &ts, 1)) != 0) 7595ac2d602Sdownsj goto bad; 7605ac2d602Sdownsj } 7615ac2d602Sdownsj error = ext2fs_direnter(ip, tdvp, tcnp); 7625ac2d602Sdownsj if (error != 0) { 7635ac2d602Sdownsj if (doingdirectory && newparent) { 7645ac2d602Sdownsj dp->i_e2fs_nlink--; 7655ac2d602Sdownsj dp->i_flag |= IN_CHANGE; 7665ac2d602Sdownsj (void)VOP_UPDATE(tdvp, &ts, &ts, 1); 7675ac2d602Sdownsj } 7685ac2d602Sdownsj goto bad; 7695ac2d602Sdownsj } 7705ac2d602Sdownsj vput(tdvp); 7715ac2d602Sdownsj } else { 7725ac2d602Sdownsj if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 7735ac2d602Sdownsj panic("rename: EXDEV"); 7745ac2d602Sdownsj /* 7755ac2d602Sdownsj * Short circuit rename(foo, foo). 7765ac2d602Sdownsj */ 7775ac2d602Sdownsj if (xp->i_number == ip->i_number) 7785ac2d602Sdownsj panic("rename: same file"); 7795ac2d602Sdownsj /* 7805ac2d602Sdownsj * If the parent directory is "sticky", then the user must 7815ac2d602Sdownsj * own the parent directory, or the destination of the rename, 7825ac2d602Sdownsj * otherwise the destination may not be changed (except by 7835ac2d602Sdownsj * root). This implements append-only directories. 7845ac2d602Sdownsj */ 7855ac2d602Sdownsj if ((dp->i_e2fs_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 && 7865ac2d602Sdownsj tcnp->cn_cred->cr_uid != dp->i_e2fs_uid && 7875ac2d602Sdownsj xp->i_e2fs_uid != tcnp->cn_cred->cr_uid) { 7885ac2d602Sdownsj error = EPERM; 7895ac2d602Sdownsj goto bad; 7905ac2d602Sdownsj } 7915ac2d602Sdownsj /* 7925ac2d602Sdownsj * Target must be empty if a directory and have no links 7935ac2d602Sdownsj * to it. Also, ensure source and target are compatible 7945ac2d602Sdownsj * (both directories, or both not directories). 7955ac2d602Sdownsj */ 7965ac2d602Sdownsj if ((xp->i_e2fs_mode & IFMT) == IFDIR) { 7975ac2d602Sdownsj if (!ext2fs_dirempty(xp, dp->i_number, tcnp->cn_cred) || 7985ac2d602Sdownsj xp->i_e2fs_nlink > 2) { 7995ac2d602Sdownsj error = ENOTEMPTY; 8005ac2d602Sdownsj goto bad; 8015ac2d602Sdownsj } 8025ac2d602Sdownsj if (!doingdirectory) { 8035ac2d602Sdownsj error = ENOTDIR; 8045ac2d602Sdownsj goto bad; 8055ac2d602Sdownsj } 8065ac2d602Sdownsj cache_purge(tdvp); 8075ac2d602Sdownsj } else if (doingdirectory) { 8085ac2d602Sdownsj error = EISDIR; 8095ac2d602Sdownsj goto bad; 8105ac2d602Sdownsj } 8115ac2d602Sdownsj error = ext2fs_dirrewrite(dp, ip, tcnp); 8125ac2d602Sdownsj if (error != 0) 8135ac2d602Sdownsj goto bad; 8145ac2d602Sdownsj /* 8155ac2d602Sdownsj * If the target directory is in the same 8165ac2d602Sdownsj * directory as the source directory, 8175ac2d602Sdownsj * decrement the link count on the parent 8185ac2d602Sdownsj * of the target directory. 8195ac2d602Sdownsj */ 8205ac2d602Sdownsj if (doingdirectory && !newparent) { 8215ac2d602Sdownsj dp->i_e2fs_nlink--; 8225ac2d602Sdownsj dp->i_flag |= IN_CHANGE; 8235ac2d602Sdownsj } 8245ac2d602Sdownsj vput(tdvp); 8255ac2d602Sdownsj /* 8265ac2d602Sdownsj * Adjust the link count of the target to 8275ac2d602Sdownsj * reflect the dirrewrite above. If this is 8285ac2d602Sdownsj * a directory it is empty and there are 8295ac2d602Sdownsj * no links to it, so we can squash the inode and 8305ac2d602Sdownsj * any space associated with it. We disallowed 8315ac2d602Sdownsj * renaming over top of a directory with links to 8325ac2d602Sdownsj * it above, as the remaining link would point to 8335ac2d602Sdownsj * a directory without "." or ".." entries. 8345ac2d602Sdownsj */ 8355ac2d602Sdownsj xp->i_e2fs_nlink--; 8365ac2d602Sdownsj if (doingdirectory) { 8375ac2d602Sdownsj if (--xp->i_e2fs_nlink != 0) 8385ac2d602Sdownsj panic("rename: linked directory"); 8395ac2d602Sdownsj error = VOP_TRUNCATE(tvp, (off_t)0, IO_SYNC, 8405ac2d602Sdownsj tcnp->cn_cred, tcnp->cn_proc); 8415ac2d602Sdownsj } 8425ac2d602Sdownsj xp->i_flag |= IN_CHANGE; 8435ac2d602Sdownsj vput(tvp); 8445ac2d602Sdownsj xp = NULL; 8455ac2d602Sdownsj } 8465ac2d602Sdownsj 8475ac2d602Sdownsj /* 8485ac2d602Sdownsj * 3) Unlink the source. 8495ac2d602Sdownsj */ 8505ac2d602Sdownsj fcnp->cn_flags &= ~MODMASK; 8515ac2d602Sdownsj fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; 8525ac2d602Sdownsj if ((fcnp->cn_flags & SAVESTART) == 0) 8535ac2d602Sdownsj panic("ext2fs_rename: lost from startdir"); 8545ac2d602Sdownsj (void) relookup(fdvp, &fvp, fcnp); 8555ac2d602Sdownsj if (fvp != NULL) { 8565ac2d602Sdownsj xp = VTOI(fvp); 8575ac2d602Sdownsj dp = VTOI(fdvp); 8585ac2d602Sdownsj } else { 8595ac2d602Sdownsj /* 8605ac2d602Sdownsj * From name has disappeared. 8615ac2d602Sdownsj */ 8625ac2d602Sdownsj if (doingdirectory) 8635ac2d602Sdownsj panic("ext2fs_rename: lost dir entry"); 8645ac2d602Sdownsj vrele(ap->a_fvp); 8655ac2d602Sdownsj return (0); 8665ac2d602Sdownsj } 8675ac2d602Sdownsj /* 8685ac2d602Sdownsj * Ensure that the directory entry still exists and has not 8695ac2d602Sdownsj * changed while the new name has been entered. If the source is 8705ac2d602Sdownsj * a file then the entry may have been unlinked or renamed. In 8715ac2d602Sdownsj * either case there is no further work to be done. If the source 8725ac2d602Sdownsj * is a directory then it cannot have been rmdir'ed; its link 8735ac2d602Sdownsj * count of three would cause a rmdir to fail with ENOTEMPTY. 8745ac2d602Sdownsj * The IRENAME flag ensures that it cannot be moved by another 8755ac2d602Sdownsj * rename. 8765ac2d602Sdownsj */ 8775ac2d602Sdownsj if (xp != ip) { 8785ac2d602Sdownsj if (doingdirectory) 8795ac2d602Sdownsj panic("ext2fs_rename: lost dir entry"); 8805ac2d602Sdownsj } else { 8815ac2d602Sdownsj /* 8825ac2d602Sdownsj * If the source is a directory with a 8835ac2d602Sdownsj * new parent, the link count of the old 8845ac2d602Sdownsj * parent directory must be decremented 8855ac2d602Sdownsj * and ".." set to point to the new parent. 8865ac2d602Sdownsj */ 8875ac2d602Sdownsj if (doingdirectory && newparent) { 8885ac2d602Sdownsj dp->i_e2fs_nlink--; 8895ac2d602Sdownsj dp->i_flag |= IN_CHANGE; 8905ac2d602Sdownsj error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf, 8915ac2d602Sdownsj sizeof (struct ext2fs_dirtemplate), (off_t)0, 8925ac2d602Sdownsj UIO_SYSSPACE, IO_NODELOCKED, 8935ac2d602Sdownsj tcnp->cn_cred, (int *)0, (struct proc *)0); 8945ac2d602Sdownsj if (error == 0) { 8955ac2d602Sdownsj namlen = dirbuf.dotdot_namlen; 8965ac2d602Sdownsj if (namlen != 2 || 8975ac2d602Sdownsj dirbuf.dotdot_name[0] != '.' || 8985ac2d602Sdownsj dirbuf.dotdot_name[1] != '.') { 8995ac2d602Sdownsj ufs_dirbad(xp, (doff_t)12, 9005ac2d602Sdownsj "ext2fs_rename: mangled dir"); 9015ac2d602Sdownsj } else { 9025ac2d602Sdownsj dirbuf.dotdot_ino = newparent; 9035ac2d602Sdownsj (void) vn_rdwr(UIO_WRITE, fvp, 9045ac2d602Sdownsj (caddr_t)&dirbuf, 9055ac2d602Sdownsj sizeof (struct dirtemplate), 9065ac2d602Sdownsj (off_t)0, UIO_SYSSPACE, 9075ac2d602Sdownsj IO_NODELOCKED|IO_SYNC, 9085ac2d602Sdownsj tcnp->cn_cred, (int *)0, 9095ac2d602Sdownsj (struct proc *)0); 9105ac2d602Sdownsj cache_purge(fdvp); 9115ac2d602Sdownsj } 9125ac2d602Sdownsj } 9135ac2d602Sdownsj } 9145ac2d602Sdownsj error = ext2fs_dirremove(fdvp, fcnp); 9155ac2d602Sdownsj if (!error) { 9165ac2d602Sdownsj xp->i_e2fs_nlink--; 9175ac2d602Sdownsj xp->i_flag |= IN_CHANGE; 9185ac2d602Sdownsj } 9195ac2d602Sdownsj xp->i_flag &= ~IN_RENAME; 9205ac2d602Sdownsj } 9215ac2d602Sdownsj if (dp) 9225ac2d602Sdownsj vput(fdvp); 9235ac2d602Sdownsj if (xp) 9245ac2d602Sdownsj vput(fvp); 9255ac2d602Sdownsj vrele(ap->a_fvp); 9265ac2d602Sdownsj return (error); 9275ac2d602Sdownsj 9285ac2d602Sdownsj bad: 9295ac2d602Sdownsj if (xp) 9305ac2d602Sdownsj vput(ITOV(xp)); 9315ac2d602Sdownsj vput(ITOV(dp)); 9325ac2d602Sdownsj out: 9335ac2d602Sdownsj if (doingdirectory) 9345ac2d602Sdownsj ip->i_flag &= ~IN_RENAME; 935*07feb63cScsapuntz if (vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p) == 0) { 9365ac2d602Sdownsj ip->i_e2fs_nlink--; 9375ac2d602Sdownsj ip->i_flag |= IN_CHANGE; 9385ac2d602Sdownsj vput(fvp); 9395ac2d602Sdownsj } else 9405ac2d602Sdownsj vrele(fvp); 9415ac2d602Sdownsj return (error); 9425ac2d602Sdownsj } 9435ac2d602Sdownsj 9445ac2d602Sdownsj /* 9455ac2d602Sdownsj * A virgin directory (no blushing please). 9465ac2d602Sdownsj */ 9475ac2d602Sdownsj static struct ext2fs_dirtemplate mastertemplate = { 9485ac2d602Sdownsj 0, 12, 1, ".", 9495ac2d602Sdownsj 0, - 12, 2, ".." /* XXX -12 should be e2fs_bsize-12 */ 9505ac2d602Sdownsj }; 9515ac2d602Sdownsj 9525ac2d602Sdownsj /* 9535ac2d602Sdownsj * Mkdir system call 9545ac2d602Sdownsj */ 9555ac2d602Sdownsj int 9565ac2d602Sdownsj ext2fs_mkdir(v) 9575ac2d602Sdownsj void *v; 9585ac2d602Sdownsj { 9595ac2d602Sdownsj struct vop_mkdir_args /* { 9605ac2d602Sdownsj struct vnode *a_dvp; 9615ac2d602Sdownsj struct vnode **a_vpp; 9625ac2d602Sdownsj struct componentname *a_cnp; 9635ac2d602Sdownsj struct vattr *a_vap; 9645ac2d602Sdownsj } */ *ap = v; 9655ac2d602Sdownsj register struct vnode *dvp = ap->a_dvp; 9665ac2d602Sdownsj register struct vattr *vap = ap->a_vap; 9675ac2d602Sdownsj register struct componentname *cnp = ap->a_cnp; 9685ac2d602Sdownsj register struct inode *ip, *dp; 9695ac2d602Sdownsj struct vnode *tvp; 9705ac2d602Sdownsj struct ext2fs_dirtemplate dirtemplate, *dtp; 9715ac2d602Sdownsj struct timespec ts; 9725ac2d602Sdownsj int error, dmode; 9735ac2d602Sdownsj 9745ac2d602Sdownsj #ifdef DIAGNOSTIC 9755ac2d602Sdownsj if ((cnp->cn_flags & HASBUF) == 0) 9765ac2d602Sdownsj panic("ext2fs_mkdir: no name"); 9775ac2d602Sdownsj #endif 9785ac2d602Sdownsj dp = VTOI(dvp); 9795ac2d602Sdownsj if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) { 9805ac2d602Sdownsj error = EMLINK; 9815ac2d602Sdownsj goto out; 9825ac2d602Sdownsj } 9831f3ff51cSdownsj dmode = vap->va_mode & ACCESSPERMS; 9845ac2d602Sdownsj dmode |= IFDIR; 9855ac2d602Sdownsj /* 9865ac2d602Sdownsj * Must simulate part of ext2fs_makeinode here to acquire the inode, 9875ac2d602Sdownsj * but not have it entered in the parent directory. The entry is 9885ac2d602Sdownsj * made later after writing "." and ".." entries. 9895ac2d602Sdownsj */ 9905ac2d602Sdownsj if ((error = VOP_VALLOC(dvp, dmode, cnp->cn_cred, &tvp)) != 0) 9915ac2d602Sdownsj goto out; 9925ac2d602Sdownsj ip = VTOI(tvp); 9935ac2d602Sdownsj ip->i_e2fs_uid = cnp->cn_cred->cr_uid; 9945ac2d602Sdownsj ip->i_e2fs_gid = dp->i_e2fs_gid; 9955ac2d602Sdownsj ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 9965ac2d602Sdownsj ip->i_e2fs_mode = dmode; 9975ac2d602Sdownsj tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ 9985ac2d602Sdownsj ip->i_e2fs_nlink = 2; 9995ac2d602Sdownsj TIMEVAL_TO_TIMESPEC(&time, &ts); 10005ac2d602Sdownsj error = VOP_UPDATE(tvp, &ts, &ts, 1); 10015ac2d602Sdownsj 10025ac2d602Sdownsj /* 10035ac2d602Sdownsj * Bump link count in parent directory 10045ac2d602Sdownsj * to reflect work done below. Should 10055ac2d602Sdownsj * be done before reference is created 10065ac2d602Sdownsj * so reparation is possible if we crash. 10075ac2d602Sdownsj */ 10085ac2d602Sdownsj dp->i_e2fs_nlink++; 10095ac2d602Sdownsj dp->i_flag |= IN_CHANGE; 10105ac2d602Sdownsj if ((error = VOP_UPDATE(dvp, &ts, &ts, 1)) != 0) 10115ac2d602Sdownsj goto bad; 10125ac2d602Sdownsj 10135ac2d602Sdownsj /* Initialize directory with "." and ".." from static template. */ 10145ac2d602Sdownsj dtp = &mastertemplate; 10155ac2d602Sdownsj dirtemplate = *dtp; 10165ac2d602Sdownsj dirtemplate.dot_ino = ip->i_number; 10175ac2d602Sdownsj dirtemplate.dotdot_ino = dp->i_number; 10185ac2d602Sdownsj /* Correct reclen of second entry */ 10195ac2d602Sdownsj dirtemplate.dotdot_reclen = VTOI(dvp)->i_e2fs->e2fs_bsize - 12; 10205ac2d602Sdownsj error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate, 10215ac2d602Sdownsj sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 10225ac2d602Sdownsj IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0); 10235ac2d602Sdownsj if (error) { 10245ac2d602Sdownsj dp->i_e2fs_nlink--; 10255ac2d602Sdownsj dp->i_flag |= IN_CHANGE; 10265ac2d602Sdownsj goto bad; 10275ac2d602Sdownsj } 10285ac2d602Sdownsj if (VTOI(dvp)->i_e2fs->e2fs_bsize > 10295ac2d602Sdownsj VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) 10305ac2d602Sdownsj panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */ 10315ac2d602Sdownsj else { 10325ac2d602Sdownsj ip->i_e2fs_size = VTOI(dvp)->i_e2fs->e2fs_bsize; 10335ac2d602Sdownsj ip->i_flag |= IN_CHANGE; 10345ac2d602Sdownsj } 10355ac2d602Sdownsj 10365ac2d602Sdownsj /* Directory set up, now install it's entry in the parent directory. */ 10375ac2d602Sdownsj error = ext2fs_direnter(ip, dvp, cnp); 10385ac2d602Sdownsj if (error != 0) { 10395ac2d602Sdownsj dp->i_e2fs_nlink--; 10405ac2d602Sdownsj dp->i_flag |= IN_CHANGE; 10415ac2d602Sdownsj } 10425ac2d602Sdownsj bad: 10435ac2d602Sdownsj /* 10445ac2d602Sdownsj * No need to do an explicit VOP_TRUNCATE here, vrele will do this 10455ac2d602Sdownsj * for us because we set the link count to 0. 10465ac2d602Sdownsj */ 10475ac2d602Sdownsj if (error) { 10485ac2d602Sdownsj ip->i_e2fs_nlink = 0; 10495ac2d602Sdownsj ip->i_flag |= IN_CHANGE; 10505ac2d602Sdownsj vput(tvp); 10515ac2d602Sdownsj } else 10525ac2d602Sdownsj *ap->a_vpp = tvp; 10535ac2d602Sdownsj out: 10545ac2d602Sdownsj FREE(cnp->cn_pnbuf, M_NAMEI); 10555ac2d602Sdownsj vput(dvp); 10565ac2d602Sdownsj return (error); 10575ac2d602Sdownsj } 10585ac2d602Sdownsj 10595ac2d602Sdownsj /* 10605ac2d602Sdownsj * Rmdir system call. 10615ac2d602Sdownsj */ 10625ac2d602Sdownsj int 10635ac2d602Sdownsj ext2fs_rmdir(v) 10645ac2d602Sdownsj void *v; 10655ac2d602Sdownsj { 10665ac2d602Sdownsj struct vop_rmdir_args /* { 10675ac2d602Sdownsj struct vnode *a_dvp; 10685ac2d602Sdownsj struct vnode *a_vp; 10695ac2d602Sdownsj struct componentname *a_cnp; 10705ac2d602Sdownsj } */ *ap = v; 10715ac2d602Sdownsj register struct vnode *vp = ap->a_vp; 10725ac2d602Sdownsj register struct vnode *dvp = ap->a_dvp; 10735ac2d602Sdownsj register struct componentname *cnp = ap->a_cnp; 10745ac2d602Sdownsj register struct inode *ip, *dp; 10755ac2d602Sdownsj int error; 10765ac2d602Sdownsj 10775ac2d602Sdownsj ip = VTOI(vp); 10785ac2d602Sdownsj dp = VTOI(dvp); 10795ac2d602Sdownsj /* 10805ac2d602Sdownsj * No rmdir "." please. 10815ac2d602Sdownsj */ 10825ac2d602Sdownsj if (dp == ip) { 10835ac2d602Sdownsj vrele(dvp); 10845ac2d602Sdownsj vput(vp); 10855ac2d602Sdownsj return (EINVAL); 10865ac2d602Sdownsj } 10875ac2d602Sdownsj /* 10885ac2d602Sdownsj * Verify the directory is empty (and valid). 10895ac2d602Sdownsj * (Rmdir ".." won't be valid since 10905ac2d602Sdownsj * ".." will contain a reference to 10915ac2d602Sdownsj * the current directory and thus be 10925ac2d602Sdownsj * non-empty.) 10935ac2d602Sdownsj */ 10945ac2d602Sdownsj error = 0; 10955ac2d602Sdownsj if (ip->i_e2fs_nlink != 2 || 10965ac2d602Sdownsj !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) { 10975ac2d602Sdownsj error = ENOTEMPTY; 10985ac2d602Sdownsj goto out; 10995ac2d602Sdownsj } 11005ac2d602Sdownsj if ((dp->i_e2fs_flags & EXT2_APPEND) || 11015ac2d602Sdownsj (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) { 11025ac2d602Sdownsj error = EPERM; 11035ac2d602Sdownsj goto out; 11045ac2d602Sdownsj } 11055ac2d602Sdownsj /* 11065ac2d602Sdownsj * Delete reference to directory before purging 11075ac2d602Sdownsj * inode. If we crash in between, the directory 11085ac2d602Sdownsj * will be reattached to lost+found, 11095ac2d602Sdownsj */ 11105ac2d602Sdownsj error = ext2fs_dirremove(dvp, cnp); 11115ac2d602Sdownsj if (error != 0) 11125ac2d602Sdownsj goto out; 11135ac2d602Sdownsj dp->i_e2fs_nlink--; 11145ac2d602Sdownsj dp->i_flag |= IN_CHANGE; 11155ac2d602Sdownsj cache_purge(dvp); 11165ac2d602Sdownsj vput(dvp); 11175ac2d602Sdownsj dvp = NULL; 11185ac2d602Sdownsj /* 11195ac2d602Sdownsj * Truncate inode. The only stuff left 11205ac2d602Sdownsj * in the directory is "." and "..". The 11215ac2d602Sdownsj * "." reference is inconsequential since 11225ac2d602Sdownsj * we're quashing it. The ".." reference 11235ac2d602Sdownsj * has already been adjusted above. We've 11245ac2d602Sdownsj * removed the "." reference and the reference 11255ac2d602Sdownsj * in the parent directory, but there may be 11265ac2d602Sdownsj * other hard links so decrement by 2 and 11275ac2d602Sdownsj * worry about them later. 11285ac2d602Sdownsj */ 11295ac2d602Sdownsj ip->i_e2fs_nlink -= 2; 11305ac2d602Sdownsj error = VOP_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, 11315ac2d602Sdownsj cnp->cn_proc); 11325ac2d602Sdownsj cache_purge(ITOV(ip)); 11335ac2d602Sdownsj out: 11345ac2d602Sdownsj if (dvp) 11355ac2d602Sdownsj vput(dvp); 11365ac2d602Sdownsj vput(vp); 11375ac2d602Sdownsj return (error); 11385ac2d602Sdownsj } 11395ac2d602Sdownsj 11405ac2d602Sdownsj /* 11415ac2d602Sdownsj * symlink -- make a symbolic link 11425ac2d602Sdownsj */ 11435ac2d602Sdownsj int 11445ac2d602Sdownsj ext2fs_symlink(v) 11455ac2d602Sdownsj void *v; 11465ac2d602Sdownsj { 11475ac2d602Sdownsj struct vop_symlink_args /* { 11485ac2d602Sdownsj struct vnode *a_dvp; 11495ac2d602Sdownsj struct vnode **a_vpp; 11505ac2d602Sdownsj struct componentname *a_cnp; 11515ac2d602Sdownsj struct vattr *a_vap; 11525ac2d602Sdownsj char *a_target; 11535ac2d602Sdownsj } */ *ap = v; 11545ac2d602Sdownsj register struct vnode *vp, **vpp = ap->a_vpp; 11555ac2d602Sdownsj register struct inode *ip; 11565ac2d602Sdownsj int len, error; 11575ac2d602Sdownsj 11585ac2d602Sdownsj error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp, 11595ac2d602Sdownsj vpp, ap->a_cnp); 11605ac2d602Sdownsj if (error) 11615ac2d602Sdownsj return (error); 11625ac2d602Sdownsj vp = *vpp; 11635ac2d602Sdownsj len = strlen(ap->a_target); 11645ac2d602Sdownsj if (len < vp->v_mount->mnt_maxsymlinklen) { 11655ac2d602Sdownsj ip = VTOI(vp); 11665ac2d602Sdownsj bcopy(ap->a_target, (char *)ip->i_din.e2fs_din.e2di_shortlink, len); 11675ac2d602Sdownsj ip->i_e2fs_size = len; 11685ac2d602Sdownsj ip->i_flag |= IN_CHANGE | IN_UPDATE; 11695ac2d602Sdownsj } else 11705ac2d602Sdownsj error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0, 11715ac2d602Sdownsj UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0, 11725ac2d602Sdownsj (struct proc *)0); 11735ac2d602Sdownsj vput(vp); 11745ac2d602Sdownsj return (error); 11755ac2d602Sdownsj } 11765ac2d602Sdownsj 11775ac2d602Sdownsj /* 11785ac2d602Sdownsj * Return target name of a symbolic link 11795ac2d602Sdownsj */ 11805ac2d602Sdownsj int 11815ac2d602Sdownsj ext2fs_readlink(v) 11825ac2d602Sdownsj void *v; 11835ac2d602Sdownsj { 11845ac2d602Sdownsj struct vop_readlink_args /* { 11855ac2d602Sdownsj struct vnode *a_vp; 11865ac2d602Sdownsj struct uio *a_uio; 11875ac2d602Sdownsj struct ucred *a_cred; 11885ac2d602Sdownsj } */ *ap = v; 11895ac2d602Sdownsj register struct vnode *vp = ap->a_vp; 11905ac2d602Sdownsj register struct inode *ip = VTOI(vp); 11915ac2d602Sdownsj int isize; 11925ac2d602Sdownsj 11935ac2d602Sdownsj isize = ip->i_e2fs_size; 11945ac2d602Sdownsj if (isize < vp->v_mount->mnt_maxsymlinklen || 11955ac2d602Sdownsj (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) { 11965ac2d602Sdownsj uiomove((char *)ip->i_din.e2fs_din.e2di_shortlink, isize, ap->a_uio); 11975ac2d602Sdownsj return (0); 11985ac2d602Sdownsj } 11995ac2d602Sdownsj return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); 12005ac2d602Sdownsj } 12015ac2d602Sdownsj 12025ac2d602Sdownsj /* 12035ac2d602Sdownsj * Advisory record locking support 12045ac2d602Sdownsj */ 12055ac2d602Sdownsj int 12065ac2d602Sdownsj ext2fs_advlock(v) 12075ac2d602Sdownsj void *v; 12085ac2d602Sdownsj { 12095ac2d602Sdownsj struct vop_advlock_args /* { 12105ac2d602Sdownsj struct vnode *a_vp; 12115ac2d602Sdownsj caddr_t a_id; 12125ac2d602Sdownsj int a_op; 12135ac2d602Sdownsj struct flock *a_fl; 12145ac2d602Sdownsj int a_flags; 12155ac2d602Sdownsj } */ *ap = v; 12165ac2d602Sdownsj register struct inode *ip = VTOI(ap->a_vp); 12175ac2d602Sdownsj 12185ac2d602Sdownsj return (lf_advlock(&ip->i_lockf, ip->i_e2fs_size, ap->a_id, ap->a_op, 12195ac2d602Sdownsj ap->a_fl, ap->a_flags)); 12205ac2d602Sdownsj } 12215ac2d602Sdownsj 12225ac2d602Sdownsj /* 12235ac2d602Sdownsj * Initialize the vnode associated with a new inode, handle aliased 12245ac2d602Sdownsj * vnodes. 12255ac2d602Sdownsj */ 12265ac2d602Sdownsj int 12275ac2d602Sdownsj ext2fs_vinit(mntp, specops, fifoops, vpp) 12285ac2d602Sdownsj struct mount *mntp; 12295ac2d602Sdownsj int (**specops) __P((void *)); 12305ac2d602Sdownsj int (**fifoops) __P((void *)); 12315ac2d602Sdownsj struct vnode **vpp; 12325ac2d602Sdownsj { 12335ac2d602Sdownsj struct inode *ip; 12345ac2d602Sdownsj struct vnode *vp, *nvp; 1235*07feb63cScsapuntz struct proc *p = curproc; 12365ac2d602Sdownsj 12375ac2d602Sdownsj vp = *vpp; 12385ac2d602Sdownsj ip = VTOI(vp); 12395ac2d602Sdownsj switch(vp->v_type = IFTOVT(ip->i_e2fs_mode)) { 12405ac2d602Sdownsj case VCHR: 12415ac2d602Sdownsj case VBLK: 12425ac2d602Sdownsj vp->v_op = specops; 12435ac2d602Sdownsj if ((nvp = checkalias(vp, ip->i_din.e2fs_din.e2di_rdev, mntp)) 12445ac2d602Sdownsj != NULL) { 12455ac2d602Sdownsj /* 12465ac2d602Sdownsj * Discard unneeded vnode, but save its inode. 12475ac2d602Sdownsj */ 12485ac2d602Sdownsj ufs_ihashrem(ip); 1249*07feb63cScsapuntz VOP_UNLOCK(vp, 0, p); 12505ac2d602Sdownsj nvp->v_data = vp->v_data; 12515ac2d602Sdownsj vp->v_data = NULL; 12525ac2d602Sdownsj vp->v_op = spec_vnodeop_p; 12535ac2d602Sdownsj vrele(vp); 12545ac2d602Sdownsj vgone(vp); 12555ac2d602Sdownsj /* 12565ac2d602Sdownsj * Reinitialize aliased inode. 12575ac2d602Sdownsj */ 12585ac2d602Sdownsj vp = nvp; 12595ac2d602Sdownsj ip->i_vnode = vp; 12605ac2d602Sdownsj ufs_ihashins(ip); 12615ac2d602Sdownsj } 12625ac2d602Sdownsj break; 12635ac2d602Sdownsj case VFIFO: 12645ac2d602Sdownsj #ifdef FIFO 12655ac2d602Sdownsj vp->v_op = fifoops; 12665ac2d602Sdownsj break; 12675ac2d602Sdownsj #else 12685ac2d602Sdownsj return (EOPNOTSUPP); 12695ac2d602Sdownsj #endif 12705ac2d602Sdownsj case VNON: 12715ac2d602Sdownsj case VBAD: 12725ac2d602Sdownsj case VSOCK: 12735ac2d602Sdownsj case VLNK: 12745ac2d602Sdownsj case VDIR: 12755ac2d602Sdownsj case VREG: 12765ac2d602Sdownsj break; 12775ac2d602Sdownsj } 12785ac2d602Sdownsj if (ip->i_number == ROOTINO) 12795ac2d602Sdownsj vp->v_flag |= VROOT; 12805ac2d602Sdownsj /* 12815ac2d602Sdownsj * Initialize modrev times 12825ac2d602Sdownsj */ 12835ac2d602Sdownsj SETHIGH(ip->i_modrev, mono_time.tv_sec); 12845ac2d602Sdownsj SETLOW(ip->i_modrev, mono_time.tv_usec * 4294); 12855ac2d602Sdownsj *vpp = vp; 12865ac2d602Sdownsj return (0); 12875ac2d602Sdownsj } 12885ac2d602Sdownsj 12895ac2d602Sdownsj /* 12905ac2d602Sdownsj * Allocate a new inode. 12915ac2d602Sdownsj */ 12925ac2d602Sdownsj int 12935ac2d602Sdownsj ext2fs_makeinode(mode, dvp, vpp, cnp) 12945ac2d602Sdownsj int mode; 12955ac2d602Sdownsj struct vnode *dvp; 12965ac2d602Sdownsj struct vnode **vpp; 12975ac2d602Sdownsj struct componentname *cnp; 12985ac2d602Sdownsj { 12995ac2d602Sdownsj register struct inode *ip, *pdir; 13005ac2d602Sdownsj struct timespec ts; 13015ac2d602Sdownsj struct vnode *tvp; 13025ac2d602Sdownsj int error; 13035ac2d602Sdownsj 13045ac2d602Sdownsj pdir = VTOI(dvp); 13055ac2d602Sdownsj #ifdef DIAGNOSTIC 13065ac2d602Sdownsj if ((cnp->cn_flags & HASBUF) == 0) 13075ac2d602Sdownsj panic("ext2fs_makeinode: no name"); 13085ac2d602Sdownsj #endif 13095ac2d602Sdownsj *vpp = NULL; 13105ac2d602Sdownsj if ((mode & IFMT) == 0) 13115ac2d602Sdownsj mode |= IFREG; 13125ac2d602Sdownsj 13135ac2d602Sdownsj if ((error = VOP_VALLOC(dvp, mode, cnp->cn_cred, &tvp)) != 0) { 13145ac2d602Sdownsj free(cnp->cn_pnbuf, M_NAMEI); 13155ac2d602Sdownsj vput(dvp); 13165ac2d602Sdownsj return (error); 13175ac2d602Sdownsj } 13185ac2d602Sdownsj ip = VTOI(tvp); 13195ac2d602Sdownsj ip->i_e2fs_gid = pdir->i_e2fs_gid; 13205ac2d602Sdownsj ip->i_e2fs_uid = cnp->cn_cred->cr_uid; 13215ac2d602Sdownsj ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 13225ac2d602Sdownsj ip->i_e2fs_mode = mode; 13235ac2d602Sdownsj tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ 13245ac2d602Sdownsj ip->i_e2fs_nlink = 1; 13255ac2d602Sdownsj if ((ip->i_e2fs_mode & ISGID) && 13265ac2d602Sdownsj !groupmember(ip->i_e2fs_gid, cnp->cn_cred) && 13275ac2d602Sdownsj suser(cnp->cn_cred, NULL)) 13285ac2d602Sdownsj ip->i_e2fs_mode &= ~ISGID; 13295ac2d602Sdownsj 13305ac2d602Sdownsj /* 13315ac2d602Sdownsj * Make sure inode goes to disk before directory entry. 13325ac2d602Sdownsj */ 13335ac2d602Sdownsj TIMEVAL_TO_TIMESPEC(&time, &ts); 13345ac2d602Sdownsj if ((error = VOP_UPDATE(tvp, &ts, &ts, 1)) != 0) 13355ac2d602Sdownsj goto bad; 13365ac2d602Sdownsj error = ext2fs_direnter(ip, dvp, cnp); 13375ac2d602Sdownsj if (error != 0) 13385ac2d602Sdownsj goto bad; 13395ac2d602Sdownsj if ((cnp->cn_flags & SAVESTART) == 0) 13405ac2d602Sdownsj FREE(cnp->cn_pnbuf, M_NAMEI); 13415ac2d602Sdownsj vput(dvp); 13425ac2d602Sdownsj *vpp = tvp; 13435ac2d602Sdownsj return (0); 13445ac2d602Sdownsj 13455ac2d602Sdownsj bad: 13465ac2d602Sdownsj /* 13475ac2d602Sdownsj * Write error occurred trying to update the inode 13485ac2d602Sdownsj * or the directory so must deallocate the inode. 13495ac2d602Sdownsj */ 13505ac2d602Sdownsj free(cnp->cn_pnbuf, M_NAMEI); 13515ac2d602Sdownsj vput(dvp); 13525ac2d602Sdownsj ip->i_e2fs_nlink = 0; 13535ac2d602Sdownsj ip->i_flag |= IN_CHANGE; 13545ac2d602Sdownsj vput(tvp); 13555ac2d602Sdownsj return (error); 13565ac2d602Sdownsj } 13575ac2d602Sdownsj 13585ac2d602Sdownsj /* 13597dc61945Sdownsj * Synch an open file. 13607dc61945Sdownsj */ 13617dc61945Sdownsj /* ARGSUSED */ 13627dc61945Sdownsj int 13637dc61945Sdownsj ext2fs_fsync(v) 13647dc61945Sdownsj void *v; 13657dc61945Sdownsj { 13667dc61945Sdownsj struct vop_fsync_args /* { 13677dc61945Sdownsj struct vnode *a_vp; 13687dc61945Sdownsj struct ucred *a_cred; 13697dc61945Sdownsj int a_waitfor; 13707dc61945Sdownsj struct proc *a_p; 13717dc61945Sdownsj } */ *ap = v; 13727dc61945Sdownsj register struct vnode *vp = ap->a_vp; 13737dc61945Sdownsj struct timespec ts; 13747dc61945Sdownsj 13757dc61945Sdownsj vflushbuf(vp, ap->a_waitfor == MNT_WAIT); 13767dc61945Sdownsj TIMEVAL_TO_TIMESPEC(&time, &ts); 13777dc61945Sdownsj return (VOP_UPDATE(ap->a_vp, &ts, &ts, ap->a_waitfor == MNT_WAIT)); 13787dc61945Sdownsj } 13797dc61945Sdownsj 13807dc61945Sdownsj /* 13815ac2d602Sdownsj * Reclaim an inode so that it can be used for other purposes. 13825ac2d602Sdownsj */ 13835ac2d602Sdownsj int 13845ac2d602Sdownsj ext2fs_reclaim(v) 13855ac2d602Sdownsj void *v; 13865ac2d602Sdownsj { 13875ac2d602Sdownsj struct vop_reclaim_args /* { 13885ac2d602Sdownsj struct vnode *a_vp; 13895ac2d602Sdownsj } */ *ap = v; 13905ac2d602Sdownsj register struct vnode *vp = ap->a_vp; 13915ac2d602Sdownsj struct inode *ip; 13925ac2d602Sdownsj extern int prtactive; 13935ac2d602Sdownsj 13945ac2d602Sdownsj if (prtactive && vp->v_usecount != 0) 13955ac2d602Sdownsj vprint("ext2fs_reclaim: pushing active", vp); 13965ac2d602Sdownsj /* 13975ac2d602Sdownsj * Remove the inode from its hash chain. 13985ac2d602Sdownsj */ 13995ac2d602Sdownsj ip = VTOI(vp); 14005ac2d602Sdownsj ufs_ihashrem(ip); 14015ac2d602Sdownsj /* 14025ac2d602Sdownsj * Purge old data structures associated with the inode. 14035ac2d602Sdownsj */ 14045ac2d602Sdownsj cache_purge(vp); 14055ac2d602Sdownsj if (ip->i_devvp) { 14065ac2d602Sdownsj vrele(ip->i_devvp); 14075ac2d602Sdownsj ip->i_devvp = 0; 14085ac2d602Sdownsj } 14095ac2d602Sdownsj 14105ac2d602Sdownsj FREE(vp->v_data, M_EXT2FSNODE); 14115ac2d602Sdownsj vp->v_data = NULL; 14125ac2d602Sdownsj return (0); 14135ac2d602Sdownsj } 14145ac2d602Sdownsj 14155ac2d602Sdownsj /* Global vfs data structures for ext2fs. */ 14165ac2d602Sdownsj int (**ext2fs_vnodeop_p) __P((void *)); 14175ac2d602Sdownsj struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = { 14185ac2d602Sdownsj { &vop_default_desc, vn_default_error }, 14195ac2d602Sdownsj { &vop_lookup_desc, ext2fs_lookup }, /* lookup */ 14205ac2d602Sdownsj { &vop_create_desc, ext2fs_create }, /* create */ 14215ac2d602Sdownsj { &vop_mknod_desc, ext2fs_mknod }, /* mknod */ 14225ac2d602Sdownsj { &vop_open_desc, ext2fs_open }, /* open */ 14235ac2d602Sdownsj { &vop_close_desc, ufs_close }, /* close */ 14245ac2d602Sdownsj { &vop_access_desc, ext2fs_access }, /* access */ 14255ac2d602Sdownsj { &vop_getattr_desc, ext2fs_getattr }, /* getattr */ 14265ac2d602Sdownsj { &vop_setattr_desc, ext2fs_setattr }, /* setattr */ 14275ac2d602Sdownsj { &vop_read_desc, ext2fs_read }, /* read */ 14285ac2d602Sdownsj { &vop_write_desc, ext2fs_write }, /* write */ 14295ac2d602Sdownsj { &vop_lease_desc, ufs_lease_check }, /* lease */ 14305ac2d602Sdownsj { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ 14317dc61945Sdownsj { &vop_select_desc, ufs_select }, /* select */ 14325ac2d602Sdownsj { &vop_mmap_desc, ufs_mmap }, /* mmap */ 14335ac2d602Sdownsj { &vop_fsync_desc, ext2fs_fsync }, /* fsync */ 14345ac2d602Sdownsj { &vop_seek_desc, ufs_seek }, /* seek */ 14355ac2d602Sdownsj { &vop_remove_desc, ext2fs_remove }, /* remove */ 14365ac2d602Sdownsj { &vop_link_desc, ext2fs_link }, /* link */ 14375ac2d602Sdownsj { &vop_rename_desc, ext2fs_rename }, /* rename */ 14385ac2d602Sdownsj { &vop_mkdir_desc, ext2fs_mkdir }, /* mkdir */ 14395ac2d602Sdownsj { &vop_rmdir_desc, ext2fs_rmdir }, /* rmdir */ 14405ac2d602Sdownsj { &vop_symlink_desc, ext2fs_symlink }, /* symlink */ 14415ac2d602Sdownsj { &vop_readdir_desc, ext2fs_readdir }, /* readdir */ 14425ac2d602Sdownsj { &vop_readlink_desc, ext2fs_readlink },/* readlink */ 14435ac2d602Sdownsj { &vop_abortop_desc, ufs_abortop }, /* abortop */ 14445ac2d602Sdownsj { &vop_inactive_desc, ext2fs_inactive },/* inactive */ 14455ac2d602Sdownsj { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 14465ac2d602Sdownsj { &vop_lock_desc, ufs_lock }, /* lock */ 14475ac2d602Sdownsj { &vop_unlock_desc, ufs_unlock }, /* unlock */ 14485ac2d602Sdownsj { &vop_bmap_desc, ext2fs_bmap }, /* bmap */ 14495ac2d602Sdownsj { &vop_strategy_desc, ufs_strategy }, /* strategy */ 14505ac2d602Sdownsj { &vop_print_desc, ufs_print }, /* print */ 14515ac2d602Sdownsj { &vop_islocked_desc, ufs_islocked }, /* islocked */ 14525ac2d602Sdownsj { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ 14535ac2d602Sdownsj { &vop_advlock_desc, ext2fs_advlock }, /* advlock */ 14545ac2d602Sdownsj { &vop_blkatoff_desc, ext2fs_blkatoff },/* blkatoff */ 14555ac2d602Sdownsj { &vop_valloc_desc, ext2fs_valloc }, /* valloc */ 14565ac2d602Sdownsj { &vop_vfree_desc, ext2fs_vfree }, /* vfree */ 14575ac2d602Sdownsj { &vop_truncate_desc, ext2fs_truncate },/* truncate */ 14585ac2d602Sdownsj { &vop_update_desc, ext2fs_update }, /* update */ 14595ac2d602Sdownsj { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 14605ac2d602Sdownsj { (struct vnodeop_desc*)NULL, (int(*) __P((void*)))NULL } 14615ac2d602Sdownsj }; 14625ac2d602Sdownsj struct vnodeopv_desc ext2fs_vnodeop_opv_desc = 14635ac2d602Sdownsj { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries }; 14645ac2d602Sdownsj 14655ac2d602Sdownsj int (**ext2fs_specop_p) __P((void *)); 14665ac2d602Sdownsj struct vnodeopv_entry_desc ext2fs_specop_entries[] = { 14675ac2d602Sdownsj { &vop_default_desc, vn_default_error }, 14685ac2d602Sdownsj { &vop_lookup_desc, spec_lookup }, /* lookup */ 14695ac2d602Sdownsj { &vop_create_desc, spec_create }, /* create */ 14705ac2d602Sdownsj { &vop_mknod_desc, spec_mknod }, /* mknod */ 14715ac2d602Sdownsj { &vop_open_desc, spec_open }, /* open */ 14725ac2d602Sdownsj { &vop_close_desc, ufsspec_close }, /* close */ 14735ac2d602Sdownsj { &vop_access_desc, ext2fs_access }, /* access */ 14745ac2d602Sdownsj { &vop_getattr_desc, ext2fs_getattr }, /* getattr */ 14755ac2d602Sdownsj { &vop_setattr_desc, ext2fs_setattr }, /* setattr */ 14765ac2d602Sdownsj { &vop_read_desc, ufsspec_read }, /* read */ 14775ac2d602Sdownsj { &vop_write_desc, ufsspec_write }, /* write */ 14785ac2d602Sdownsj { &vop_lease_desc, spec_lease_check }, /* lease */ 14795ac2d602Sdownsj { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 14807dc61945Sdownsj { &vop_select_desc, spec_select }, /* poll */ 14815ac2d602Sdownsj { &vop_mmap_desc, spec_mmap }, /* mmap */ 14825ac2d602Sdownsj { &vop_fsync_desc, ext2fs_fsync }, /* fsync */ 14835ac2d602Sdownsj { &vop_seek_desc, spec_seek }, /* seek */ 14845ac2d602Sdownsj { &vop_remove_desc, spec_remove }, /* remove */ 14855ac2d602Sdownsj { &vop_link_desc, spec_link }, /* link */ 14865ac2d602Sdownsj { &vop_rename_desc, spec_rename }, /* rename */ 14875ac2d602Sdownsj { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 14885ac2d602Sdownsj { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 14895ac2d602Sdownsj { &vop_symlink_desc, spec_symlink }, /* symlink */ 14905ac2d602Sdownsj { &vop_readdir_desc, spec_readdir }, /* readdir */ 14915ac2d602Sdownsj { &vop_readlink_desc, spec_readlink }, /* readlink */ 14925ac2d602Sdownsj { &vop_abortop_desc, spec_abortop }, /* abortop */ 14935ac2d602Sdownsj { &vop_inactive_desc, ext2fs_inactive },/* inactive */ 14945ac2d602Sdownsj { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 14955ac2d602Sdownsj { &vop_lock_desc, ufs_lock }, /* lock */ 14965ac2d602Sdownsj { &vop_unlock_desc, ufs_unlock }, /* unlock */ 14975ac2d602Sdownsj { &vop_bmap_desc, spec_bmap }, /* bmap */ 14985ac2d602Sdownsj { &vop_strategy_desc, spec_strategy }, /* strategy */ 14995ac2d602Sdownsj { &vop_print_desc, ufs_print }, /* print */ 15005ac2d602Sdownsj { &vop_islocked_desc, ufs_islocked }, /* islocked */ 15015ac2d602Sdownsj { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 15025ac2d602Sdownsj { &vop_advlock_desc, spec_advlock }, /* advlock */ 15035ac2d602Sdownsj { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 15045ac2d602Sdownsj { &vop_valloc_desc, spec_valloc }, /* valloc */ 15055ac2d602Sdownsj { &vop_vfree_desc, ext2fs_vfree }, /* vfree */ 15065ac2d602Sdownsj { &vop_truncate_desc, spec_truncate }, /* truncate */ 15075ac2d602Sdownsj { &vop_update_desc, ext2fs_update }, /* update */ 15085ac2d602Sdownsj { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 15095ac2d602Sdownsj { (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL } 15105ac2d602Sdownsj }; 15115ac2d602Sdownsj struct vnodeopv_desc ext2fs_specop_opv_desc = 15125ac2d602Sdownsj { &ext2fs_specop_p, ext2fs_specop_entries }; 15135ac2d602Sdownsj 15145ac2d602Sdownsj #ifdef FIFO 15155ac2d602Sdownsj int (**ext2fs_fifoop_p) __P((void *)); 15165ac2d602Sdownsj struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = { 15175ac2d602Sdownsj { &vop_default_desc, vn_default_error }, 15185ac2d602Sdownsj { &vop_lookup_desc, fifo_lookup }, /* lookup */ 15195ac2d602Sdownsj { &vop_create_desc, fifo_create }, /* create */ 15205ac2d602Sdownsj { &vop_mknod_desc, fifo_mknod }, /* mknod */ 15215ac2d602Sdownsj { &vop_open_desc, fifo_open }, /* open */ 15225ac2d602Sdownsj { &vop_close_desc, ufsfifo_close }, /* close */ 15235ac2d602Sdownsj { &vop_access_desc, ext2fs_access }, /* access */ 15245ac2d602Sdownsj { &vop_getattr_desc, ext2fs_getattr }, /* getattr */ 15255ac2d602Sdownsj { &vop_setattr_desc, ext2fs_setattr }, /* setattr */ 15265ac2d602Sdownsj { &vop_read_desc, ufsfifo_read }, /* read */ 15275ac2d602Sdownsj { &vop_write_desc, ufsfifo_write }, /* write */ 15285ac2d602Sdownsj { &vop_lease_desc, fifo_lease_check }, /* lease */ 15295ac2d602Sdownsj { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 15307dc61945Sdownsj { &vop_select_desc, fifo_select }, /* select */ 15315ac2d602Sdownsj { &vop_mmap_desc, fifo_mmap }, /* mmap */ 15325ac2d602Sdownsj { &vop_fsync_desc, ext2fs_fsync }, /* fsync */ 15335ac2d602Sdownsj { &vop_seek_desc, fifo_seek }, /* seek */ 15345ac2d602Sdownsj { &vop_remove_desc, fifo_remove }, /* remove */ 15355ac2d602Sdownsj { &vop_link_desc, fifo_link }, /* link */ 15365ac2d602Sdownsj { &vop_rename_desc, fifo_rename }, /* rename */ 15375ac2d602Sdownsj { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 15385ac2d602Sdownsj { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 15395ac2d602Sdownsj { &vop_symlink_desc, fifo_symlink }, /* symlink */ 15405ac2d602Sdownsj { &vop_readdir_desc, fifo_readdir }, /* readdir */ 15415ac2d602Sdownsj { &vop_readlink_desc, fifo_readlink }, /* readlink */ 15425ac2d602Sdownsj { &vop_abortop_desc, fifo_abortop }, /* abortop */ 15435ac2d602Sdownsj { &vop_inactive_desc, ext2fs_inactive },/* inactive */ 15445ac2d602Sdownsj { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */ 15455ac2d602Sdownsj { &vop_lock_desc, ufs_lock }, /* lock */ 15465ac2d602Sdownsj { &vop_unlock_desc, ufs_unlock }, /* unlock */ 15475ac2d602Sdownsj { &vop_bmap_desc, fifo_bmap }, /* bmap */ 15485ac2d602Sdownsj { &vop_strategy_desc, fifo_strategy }, /* strategy */ 15495ac2d602Sdownsj { &vop_print_desc, ufs_print }, /* print */ 15505ac2d602Sdownsj { &vop_islocked_desc, ufs_islocked }, /* islocked */ 15515ac2d602Sdownsj { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 15525ac2d602Sdownsj { &vop_advlock_desc, fifo_advlock }, /* advlock */ 15535ac2d602Sdownsj { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 15545ac2d602Sdownsj { &vop_valloc_desc, fifo_valloc }, /* valloc */ 15555ac2d602Sdownsj { &vop_vfree_desc, ext2fs_vfree }, /* vfree */ 15565ac2d602Sdownsj { &vop_truncate_desc, fifo_truncate }, /* truncate */ 15575ac2d602Sdownsj { &vop_update_desc, ext2fs_update }, /* update */ 15585ac2d602Sdownsj { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 15595ac2d602Sdownsj { (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL } 15605ac2d602Sdownsj }; 15615ac2d602Sdownsj struct vnodeopv_desc ext2fs_fifoop_opv_desc = 15625ac2d602Sdownsj { &ext2fs_fifoop_p, ext2fs_fifoop_entries }; 15635ac2d602Sdownsj #endif /* FIFO */ 1564