123405Smckusick /* 237737Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337737Smckusick * All rights reserved. 423405Smckusick * 537737Smckusick * Redistribution and use in source and binary forms are permitted 637737Smckusick * provided that the above copyright notice and this paragraph are 737737Smckusick * duplicated in all such forms and that any documentation, 837737Smckusick * advertising materials, and other materials related to such 937737Smckusick * distribution and use acknowledge that the software was developed 1037737Smckusick * by the University of California, Berkeley. The name of the 1137737Smckusick * University may not be used to endorse or promote products derived 1237737Smckusick * from this software without specific prior written permission. 1337737Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437737Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537737Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637737Smckusick * 17*41312Smckusick * @(#)lfs_vnops.c 7.36 (Berkeley) 05/02/90 1823405Smckusick */ 1937Sbill 2017101Sbloom #include "param.h" 2117101Sbloom #include "systm.h" 2217101Sbloom #include "user.h" 2317101Sbloom #include "kernel.h" 2417101Sbloom #include "file.h" 2517101Sbloom #include "stat.h" 2617101Sbloom #include "buf.h" 2717101Sbloom #include "proc.h" 2817101Sbloom #include "socket.h" 2917101Sbloom #include "socketvar.h" 3037737Smckusick #include "conf.h" 3117101Sbloom #include "mount.h" 3237737Smckusick #include "vnode.h" 3340653Smckusick #include "specdev.h" 34*41312Smckusick #include "../ufs/quota.h" 3537737Smckusick #include "../ufs/inode.h" 3637737Smckusick #include "../ufs/fs.h" 3737Sbill 389167Ssam /* 3937737Smckusick * Global vfs data structures for ufs 409167Ssam */ 416254Sroot 4237737Smckusick int ufs_lookup(), 4337737Smckusick ufs_create(), 4437737Smckusick ufs_mknod(), 4537737Smckusick ufs_open(), 4637737Smckusick ufs_close(), 4737737Smckusick ufs_access(), 4837737Smckusick ufs_getattr(), 4937737Smckusick ufs_setattr(), 5037737Smckusick ufs_read(), 5137737Smckusick ufs_write(), 5237737Smckusick ufs_ioctl(), 5337737Smckusick ufs_select(), 5437737Smckusick ufs_mmap(), 5537737Smckusick ufs_fsync(), 5637737Smckusick ufs_seek(), 5737737Smckusick ufs_remove(), 5837737Smckusick ufs_link(), 5937737Smckusick ufs_rename(), 6037737Smckusick ufs_mkdir(), 6137737Smckusick ufs_rmdir(), 6237737Smckusick ufs_symlink(), 6337737Smckusick ufs_readdir(), 6437737Smckusick ufs_readlink(), 6537737Smckusick ufs_abortop(), 6637737Smckusick ufs_inactive(), 6739391Smckusick ufs_reclaim(), 6837737Smckusick ufs_lock(), 6937737Smckusick ufs_unlock(), 7037737Smckusick ufs_bmap(), 7139674Smckusick ufs_strategy(), 7239909Smckusick ufs_print(), 7339909Smckusick ufs_islocked(); 746254Sroot 7537737Smckusick struct vnodeops ufs_vnodeops = { 7639674Smckusick ufs_lookup, /* lookup */ 7739674Smckusick ufs_create, /* create */ 7839674Smckusick ufs_mknod, /* mknod */ 7939674Smckusick ufs_open, /* open */ 8039674Smckusick ufs_close, /* close */ 8139674Smckusick ufs_access, /* access */ 8239674Smckusick ufs_getattr, /* getattr */ 8339674Smckusick ufs_setattr, /* setattr */ 8439674Smckusick ufs_read, /* read */ 8539674Smckusick ufs_write, /* write */ 8639674Smckusick ufs_ioctl, /* ioctl */ 8739674Smckusick ufs_select, /* select */ 8839674Smckusick ufs_mmap, /* mmap */ 8939674Smckusick ufs_fsync, /* fsync */ 9039674Smckusick ufs_seek, /* seek */ 9139674Smckusick ufs_remove, /* remove */ 9239674Smckusick ufs_link, /* link */ 9339674Smckusick ufs_rename, /* rename */ 9439674Smckusick ufs_mkdir, /* mkdir */ 9539674Smckusick ufs_rmdir, /* rmdir */ 9639674Smckusick ufs_symlink, /* symlink */ 9739674Smckusick ufs_readdir, /* readdir */ 9839674Smckusick ufs_readlink, /* readlink */ 9939674Smckusick ufs_abortop, /* abortop */ 10039674Smckusick ufs_inactive, /* inactive */ 10139674Smckusick ufs_reclaim, /* reclaim */ 10239674Smckusick ufs_lock, /* lock */ 10339674Smckusick ufs_unlock, /* unlock */ 10439674Smckusick ufs_bmap, /* bmap */ 10539674Smckusick ufs_strategy, /* strategy */ 10639674Smckusick ufs_print, /* print */ 10739909Smckusick ufs_islocked, /* islocked */ 10837737Smckusick }; 1096254Sroot 11039435Smckusick int spec_lookup(), 11139435Smckusick spec_open(), 11239628Smckusick ufsspec_read(), 11339628Smckusick ufsspec_write(), 11439435Smckusick spec_strategy(), 11539674Smckusick spec_bmap(), 11639435Smckusick spec_ioctl(), 11739435Smckusick spec_select(), 11839628Smckusick ufsspec_close(), 11939435Smckusick spec_badop(), 12039435Smckusick spec_nullop(); 12139435Smckusick 12239435Smckusick struct vnodeops spec_inodeops = { 12339597Smckusick spec_lookup, /* lookup */ 12439597Smckusick spec_badop, /* create */ 12539597Smckusick spec_badop, /* mknod */ 12639597Smckusick spec_open, /* open */ 12739628Smckusick ufsspec_close, /* close */ 12839597Smckusick ufs_access, /* access */ 12939597Smckusick ufs_getattr, /* getattr */ 13039597Smckusick ufs_setattr, /* setattr */ 13139628Smckusick ufsspec_read, /* read */ 13239628Smckusick ufsspec_write, /* write */ 13339597Smckusick spec_ioctl, /* ioctl */ 13439597Smckusick spec_select, /* select */ 13539597Smckusick spec_badop, /* mmap */ 13639597Smckusick spec_nullop, /* fsync */ 13739597Smckusick spec_badop, /* seek */ 13839597Smckusick spec_badop, /* remove */ 13939597Smckusick spec_badop, /* link */ 14039597Smckusick spec_badop, /* rename */ 14139597Smckusick spec_badop, /* mkdir */ 14239597Smckusick spec_badop, /* rmdir */ 14339597Smckusick spec_badop, /* symlink */ 14439597Smckusick spec_badop, /* readdir */ 14539597Smckusick spec_badop, /* readlink */ 14639597Smckusick spec_badop, /* abortop */ 14739597Smckusick ufs_inactive, /* inactive */ 14839597Smckusick ufs_reclaim, /* reclaim */ 14939597Smckusick ufs_lock, /* lock */ 15039597Smckusick ufs_unlock, /* unlock */ 15139674Smckusick spec_bmap, /* bmap */ 15239597Smckusick spec_strategy, /* strategy */ 15339674Smckusick ufs_print, /* print */ 15439909Smckusick ufs_islocked, /* islocked */ 15539435Smckusick }; 15639435Smckusick 15740290Smckusick #ifdef FIFO 15840290Smckusick int fifo_lookup(), 15940290Smckusick fifo_open(), 16040290Smckusick ufsfifo_read(), 16140290Smckusick ufsfifo_write(), 16240290Smckusick fifo_bmap(), 16340290Smckusick fifo_ioctl(), 16440290Smckusick fifo_select(), 16540290Smckusick ufsfifo_close(), 16640290Smckusick fifo_print(), 16740290Smckusick fifo_badop(), 16840290Smckusick fifo_nullop(); 16940290Smckusick 17040290Smckusick struct vnodeops fifo_inodeops = { 17140290Smckusick fifo_lookup, /* lookup */ 17240290Smckusick fifo_badop, /* create */ 17340290Smckusick fifo_badop, /* mknod */ 17440290Smckusick fifo_open, /* open */ 17540290Smckusick ufsfifo_close, /* close */ 17640290Smckusick ufs_access, /* access */ 17740290Smckusick ufs_getattr, /* getattr */ 17840290Smckusick ufs_setattr, /* setattr */ 17940290Smckusick ufsfifo_read, /* read */ 18040290Smckusick ufsfifo_write, /* write */ 18140290Smckusick fifo_ioctl, /* ioctl */ 18240290Smckusick fifo_select, /* select */ 18340290Smckusick fifo_badop, /* mmap */ 18440290Smckusick fifo_nullop, /* fsync */ 18540290Smckusick fifo_badop, /* seek */ 18640290Smckusick fifo_badop, /* remove */ 18740290Smckusick fifo_badop, /* link */ 18840290Smckusick fifo_badop, /* rename */ 18940290Smckusick fifo_badop, /* mkdir */ 19040290Smckusick fifo_badop, /* rmdir */ 19140290Smckusick fifo_badop, /* symlink */ 19240290Smckusick fifo_badop, /* readdir */ 19340290Smckusick fifo_badop, /* readlink */ 19440290Smckusick fifo_badop, /* abortop */ 19540290Smckusick ufs_inactive, /* inactive */ 19640290Smckusick ufs_reclaim, /* reclaim */ 19740290Smckusick ufs_lock, /* lock */ 19840290Smckusick ufs_unlock, /* unlock */ 19940290Smckusick fifo_bmap, /* bmap */ 20040290Smckusick fifo_badop, /* strategy */ 20140290Smckusick ufs_print, /* print */ 20240290Smckusick ufs_islocked, /* islocked */ 20337737Smckusick }; 20440290Smckusick #endif /* FIFO */ 20540290Smckusick 20640290Smckusick enum vtype iftovt_tab[16] = { 20740290Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 20840290Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 20937737Smckusick }; 21040290Smckusick int vttoif_tab[9] = { 21140290Smckusick 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT, 21240290Smckusick }; 2136254Sroot 2149167Ssam /* 21537737Smckusick * Create a regular file 2169167Ssam */ 21737737Smckusick ufs_create(ndp, vap) 21837737Smckusick struct nameidata *ndp; 21937737Smckusick struct vattr *vap; 2206254Sroot { 22137737Smckusick struct inode *ip; 22237737Smckusick int error; 2236254Sroot 22437737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 22537737Smckusick return (error); 22637737Smckusick ndp->ni_vp = ITOV(ip); 22737737Smckusick return (0); 2286254Sroot } 2296254Sroot 23037Sbill /* 23137737Smckusick * Mknod vnode call 2326254Sroot */ 23337737Smckusick /* ARGSUSED */ 23437737Smckusick ufs_mknod(ndp, vap, cred) 23537737Smckusick struct nameidata *ndp; 23637737Smckusick struct ucred *cred; 23737737Smckusick struct vattr *vap; 2386254Sroot { 23939435Smckusick register struct vnode *vp; 24037737Smckusick struct inode *ip; 24137737Smckusick int error; 2426254Sroot 24337737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 24437737Smckusick return (error); 24540290Smckusick ip->i_flag |= IACC|IUPD|ICHG; 24640290Smckusick if (vap->va_rdev != VNOVAL) { 24737737Smckusick /* 24837737Smckusick * Want to be able to use this to make badblock 24937737Smckusick * inodes, so don't truncate the dev number. 25037737Smckusick */ 25139608Smckusick ip->i_rdev = vap->va_rdev; 25212756Ssam } 25337737Smckusick /* 25437737Smckusick * Remove inode so that it will be reloaded by iget and 25537737Smckusick * checked to see if it is an alias of an existing entry 25637737Smckusick * in the inode cache. 25737737Smckusick */ 25840290Smckusick vp = ITOV(ip); 25940290Smckusick vput(vp); 26039435Smckusick vp->v_type = VNON; 26139435Smckusick vgone(vp); 26237737Smckusick return (0); 2636254Sroot } 2646254Sroot 2656254Sroot /* 26637737Smckusick * Open called. 26737737Smckusick * 26837737Smckusick * Nothing to do. 2696254Sroot */ 27037737Smckusick /* ARGSUSED */ 27137737Smckusick ufs_open(vp, mode, cred) 27237737Smckusick struct vnode *vp; 27337737Smckusick int mode; 27437737Smckusick struct ucred *cred; 2756254Sroot { 2766254Sroot 27737737Smckusick return (0); 2786254Sroot } 2796254Sroot 2806254Sroot /* 28137737Smckusick * Close called 28237737Smckusick * 28337737Smckusick * Update the times on the inode. 2846254Sroot */ 28537737Smckusick /* ARGSUSED */ 28637737Smckusick ufs_close(vp, fflag, cred) 28737737Smckusick struct vnode *vp; 28837737Smckusick int fflag; 28937737Smckusick struct ucred *cred; 2906254Sroot { 29137737Smckusick register struct inode *ip = VTOI(vp); 2926254Sroot 29339815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 29437737Smckusick ITIMES(ip, &time, &time); 29537737Smckusick return (0); 2966254Sroot } 2976254Sroot 298*41312Smckusick /* 299*41312Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 300*41312Smckusick * The mode is shifted to select the owner/group/other fields. The 301*41312Smckusick * super user is granted all permissions. 302*41312Smckusick */ 30337737Smckusick ufs_access(vp, mode, cred) 30437737Smckusick struct vnode *vp; 305*41312Smckusick register int mode; 30637737Smckusick struct ucred *cred; 3076254Sroot { 308*41312Smckusick register struct inode *ip = VTOI(vp); 309*41312Smckusick register gid_t *gp; 310*41312Smckusick int i, error; 3116254Sroot 312*41312Smckusick #ifdef DIAGNOSTIC 313*41312Smckusick if (!VOP_ISLOCKED(vp)) { 314*41312Smckusick vprint("ufs_access: not locked", vp); 315*41312Smckusick panic("ufs_access: not locked"); 316*41312Smckusick } 317*41312Smckusick #endif 318*41312Smckusick #ifdef QUOTA 319*41312Smckusick if (mode & VWRITE) { 320*41312Smckusick switch (vp->v_type) { 321*41312Smckusick case VREG: case VDIR: case VLNK: 322*41312Smckusick if (error = getinoquota(ip)) 323*41312Smckusick return (error); 324*41312Smckusick } 325*41312Smckusick } 326*41312Smckusick #endif /* QUOTA */ 327*41312Smckusick /* 328*41312Smckusick * If you're the super-user, you always get access. 329*41312Smckusick */ 330*41312Smckusick if (cred->cr_uid == 0) 331*41312Smckusick return (0); 332*41312Smckusick /* 333*41312Smckusick * Access check is based on only one of owner, group, public. 334*41312Smckusick * If not owner, then check group. If not a member of the 335*41312Smckusick * group, then check public access. 336*41312Smckusick */ 337*41312Smckusick if (cred->cr_uid != ip->i_uid) { 338*41312Smckusick mode >>= 3; 339*41312Smckusick gp = cred->cr_groups; 340*41312Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 341*41312Smckusick if (ip->i_gid == *gp) 342*41312Smckusick goto found; 343*41312Smckusick mode >>= 3; 344*41312Smckusick found: 345*41312Smckusick ; 346*41312Smckusick } 347*41312Smckusick if ((ip->i_mode & mode) != 0) 348*41312Smckusick return (0); 349*41312Smckusick return (EACCES); 3506254Sroot } 3516254Sroot 35237737Smckusick /* ARGSUSED */ 35337737Smckusick ufs_getattr(vp, vap, cred) 35437737Smckusick struct vnode *vp; 35537737Smckusick register struct vattr *vap; 35637737Smckusick struct ucred *cred; 3576254Sroot { 35837737Smckusick register struct inode *ip = VTOI(vp); 3596254Sroot 36037737Smckusick ITIMES(ip, &time, &time); 3616254Sroot /* 36237737Smckusick * Copy from inode table 3636254Sroot */ 36437737Smckusick vap->va_fsid = ip->i_dev; 36537737Smckusick vap->va_fileid = ip->i_number; 36637737Smckusick vap->va_mode = ip->i_mode & ~IFMT; 36737737Smckusick vap->va_nlink = ip->i_nlink; 36837737Smckusick vap->va_uid = ip->i_uid; 36937737Smckusick vap->va_gid = ip->i_gid; 37037737Smckusick vap->va_rdev = (dev_t)ip->i_rdev; 371*41312Smckusick #ifdef tahoe 372*41312Smckusick vap->va_size = ip->i_size; 373*41312Smckusick vap->va_size_rsv = 0; 374*41312Smckusick #else 37540641Smckusick vap->va_qsize = ip->i_din.di_qsize; 376*41312Smckusick #endif 37737737Smckusick vap->va_atime.tv_sec = ip->i_atime; 37838578Smckusick vap->va_atime.tv_usec = 0; 37937737Smckusick vap->va_mtime.tv_sec = ip->i_mtime; 38038578Smckusick vap->va_mtime.tv_usec = 0; 38137737Smckusick vap->va_ctime.tv_sec = ip->i_ctime; 38238578Smckusick vap->va_ctime.tv_usec = 0; 38338254Smckusick vap->va_flags = ip->i_flags; 38438254Smckusick vap->va_gen = ip->i_gen; 38537737Smckusick /* this doesn't belong here */ 38637737Smckusick if (vp->v_type == VBLK) 38737737Smckusick vap->va_blocksize = BLKDEV_IOSIZE; 38837737Smckusick else if (vp->v_type == VCHR) 38937737Smckusick vap->va_blocksize = MAXBSIZE; 3907142Smckusick else 39137737Smckusick vap->va_blocksize = ip->i_fs->fs_bsize; 39238657Smckusick vap->va_bytes = dbtob(ip->i_blocks); 39340641Smckusick vap->va_bytes_rsv = 0; 39437737Smckusick vap->va_type = vp->v_type; 39537737Smckusick return (0); 3966254Sroot } 3976254Sroot 3986254Sroot /* 39937737Smckusick * Set attribute vnode op. called from several syscalls 4006254Sroot */ 40137737Smckusick ufs_setattr(vp, vap, cred) 40237737Smckusick register struct vnode *vp; 40337737Smckusick register struct vattr *vap; 40437737Smckusick register struct ucred *cred; 4056254Sroot { 40637737Smckusick register struct inode *ip = VTOI(vp); 40737737Smckusick int error = 0; 4086254Sroot 40937737Smckusick /* 41037737Smckusick * Check for unsetable attributes. 41137737Smckusick */ 41237737Smckusick if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 41337737Smckusick (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 41437737Smckusick (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 41538254Smckusick ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 41637737Smckusick return (EINVAL); 41716540Ssam } 41837737Smckusick /* 41937737Smckusick * Go through the fields and update iff not VNOVAL. 42037737Smckusick */ 42137737Smckusick if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) 42237737Smckusick if (error = chown1(vp, vap->va_uid, vap->va_gid, cred)) 42337737Smckusick return (error); 42437737Smckusick if (vap->va_size != VNOVAL) { 42537737Smckusick if (vp->v_type == VDIR) 42637737Smckusick return (EISDIR); 42739674Smckusick if (error = itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */ 42837737Smckusick return (error); 42913878Ssam } 43037737Smckusick if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 43137773Smckusick if (cred->cr_uid != ip->i_uid && 43237773Smckusick (error = suser(cred, &u.u_acflag))) 43337773Smckusick return (error); 43437737Smckusick if (vap->va_atime.tv_sec != VNOVAL) 43537737Smckusick ip->i_flag |= IACC; 43637737Smckusick if (vap->va_mtime.tv_sec != VNOVAL) 43737737Smckusick ip->i_flag |= IUPD; 43837737Smckusick ip->i_flag |= ICHG; 43937737Smckusick if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) 44037737Smckusick return (error); 4416254Sroot } 44237737Smckusick if (vap->va_mode != (u_short)VNOVAL) 44337737Smckusick error = chmod1(vp, (int)vap->va_mode, cred); 44438254Smckusick if (vap->va_flags != VNOVAL) { 44538254Smckusick if (cred->cr_uid != ip->i_uid && 44638254Smckusick (error = suser(cred, &u.u_acflag))) 44738254Smckusick return (error); 44838254Smckusick if (cred->cr_uid == 0) { 44938254Smckusick ip->i_flags = vap->va_flags; 45038254Smckusick } else { 45138254Smckusick ip->i_flags &= 0xffff0000; 45238254Smckusick ip->i_flags |= (vap->va_flags & 0xffff); 45338254Smckusick } 45438254Smckusick ip->i_flag |= ICHG; 45538254Smckusick } 45637737Smckusick return (error); 4576254Sroot } 4586254Sroot 4596254Sroot /* 4609167Ssam * Change the mode on a file. 4619167Ssam * Inode must be locked before calling. 4629167Ssam */ 46337737Smckusick chmod1(vp, mode, cred) 46437737Smckusick register struct vnode *vp; 4657701Ssam register int mode; 46637737Smckusick struct ucred *cred; 4677701Ssam { 46837737Smckusick register struct inode *ip = VTOI(vp); 46937773Smckusick int error; 4707868Sroot 47137773Smckusick if (cred->cr_uid != ip->i_uid && 47237773Smckusick (error = suser(cred, &u.u_acflag))) 47337773Smckusick return (error); 4746254Sroot ip->i_mode &= ~07777; 47537737Smckusick if (cred->cr_uid) { 47637737Smckusick if (vp->v_type != VDIR) 47721015Smckusick mode &= ~ISVTX; 47837737Smckusick if (!groupmember(ip->i_gid, cred)) 47911811Ssam mode &= ~ISGID; 4807439Sroot } 48137737Smckusick ip->i_mode |= mode & 07777; 4826254Sroot ip->i_flag |= ICHG; 48337737Smckusick if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) 48437737Smckusick xrele(vp); 48521015Smckusick return (0); 4865992Swnj } 4875992Swnj 4889167Ssam /* 4897701Ssam * Perform chown operation on inode ip; 4907701Ssam * inode must be locked prior to call. 4917701Ssam */ 49237737Smckusick chown1(vp, uid, gid, cred) 49337737Smckusick register struct vnode *vp; 49437737Smckusick uid_t uid; 49537737Smckusick gid_t gid; 49637737Smckusick struct ucred *cred; 4977701Ssam { 49837737Smckusick register struct inode *ip = VTOI(vp); 499*41312Smckusick uid_t ouid; 500*41312Smckusick gid_t ogid; 501*41312Smckusick int error = 0; 5027701Ssam #ifdef QUOTA 503*41312Smckusick register int i; 504*41312Smckusick long change; 50511811Ssam #endif 5067701Ssam 50737737Smckusick if (uid == (u_short)VNOVAL) 50811811Ssam uid = ip->i_uid; 50937737Smckusick if (gid == (u_short)VNOVAL) 51011811Ssam gid = ip->i_gid; 51136614Sbostic /* 51236614Sbostic * If we don't own the file, are trying to change the owner 51336614Sbostic * of the file, or are not a member of the target group, 51436614Sbostic * the caller must be superuser or the call fails. 51536614Sbostic */ 51637737Smckusick if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || 51737737Smckusick !groupmember((gid_t)gid, cred)) && 51837737Smckusick (error = suser(cred, &u.u_acflag))) 51937737Smckusick return (error); 520*41312Smckusick ouid = ip->i_uid; 521*41312Smckusick ogid = ip->i_gid; 52211811Ssam #ifdef QUOTA 523*41312Smckusick if (error = getinoquota(ip)) 524*41312Smckusick return (error); 525*41312Smckusick if (ouid == uid) { 526*41312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 527*41312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 528*41312Smckusick } 529*41312Smckusick if (ogid == gid) { 530*41312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 531*41312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 532*41312Smckusick } 533*41312Smckusick change = ip->i_blocks; 534*41312Smckusick (void) chkdq(ip, -change, cred, CHOWN); 535*41312Smckusick (void) chkiq(ip, -1, cred, CHOWN); 536*41312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 537*41312Smckusick dqrele(vp, ip->i_dquot[i]); 538*41312Smckusick ip->i_dquot[i] = NODQUOT; 539*41312Smckusick } 5407482Skre #endif 54111811Ssam ip->i_uid = uid; 54211811Ssam ip->i_gid = gid; 5437701Ssam #ifdef QUOTA 544*41312Smckusick if ((error = getinoquota(ip)) == 0) { 545*41312Smckusick if (ouid == uid) { 546*41312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 547*41312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 548*41312Smckusick } 549*41312Smckusick if (ogid == gid) { 550*41312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 551*41312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 552*41312Smckusick } 553*41312Smckusick if ((error = chkdq(ip, change, cred, CHOWN)) == 0) { 554*41312Smckusick if ((error = chkiq(ip, 1, cred, CHOWN)) == 0) 555*41312Smckusick return (0); 556*41312Smckusick else 557*41312Smckusick (void) chkdq(ip, -change, cred, CHOWN|FORCE); 558*41312Smckusick } 559*41312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 560*41312Smckusick dqrele(vp, ip->i_dquot[i]); 561*41312Smckusick ip->i_dquot[i] = NODQUOT; 562*41312Smckusick } 563*41312Smckusick } 564*41312Smckusick ip->i_uid = ouid; 565*41312Smckusick ip->i_gid = ogid; 566*41312Smckusick if (getinoquota(ip) == 0) { 567*41312Smckusick if (ouid == uid) { 568*41312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 569*41312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 570*41312Smckusick } 571*41312Smckusick if (ogid == gid) { 572*41312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 573*41312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 574*41312Smckusick } 575*41312Smckusick (void) chkdq(ip, change, cred, FORCE); 576*41312Smckusick (void) chkiq(ip, 1, cred, FORCE); 577*41312Smckusick } 578*41312Smckusick if (error) 579*41312Smckusick return (error); 580*41312Smckusick #endif 581*41312Smckusick if (ouid != uid || ogid != gid) 582*41312Smckusick ip->i_flag |= ICHG; 583*41312Smckusick if (ouid != uid && cred->cr_uid != 0) 584*41312Smckusick ip->i_mode &= ~ISUID; 585*41312Smckusick if (ogid != gid && cred->cr_uid != 0) 586*41312Smckusick ip->i_mode &= ~ISGID; 58712646Ssam return (0); 58837Sbill } 58937Sbill 59039608Smckusick /* 59139608Smckusick * Vnode op for reading. 59239608Smckusick */ 59337737Smckusick /* ARGSUSED */ 59439608Smckusick ufs_read(vp, uio, ioflag, cred) 59539608Smckusick struct vnode *vp; 59639608Smckusick register struct uio *uio; 59739608Smckusick int ioflag; 59839608Smckusick struct ucred *cred; 59939608Smckusick { 60039608Smckusick register struct inode *ip = VTOI(vp); 60139608Smckusick register struct fs *fs; 60239608Smckusick struct buf *bp; 60339608Smckusick daddr_t lbn, bn, rablock; 60439896Smckusick int size, diff, error = 0; 60539608Smckusick long n, on, type; 60639608Smckusick 60739608Smckusick if (uio->uio_rw != UIO_READ) 60839608Smckusick panic("ufs_read mode"); 60939608Smckusick type = ip->i_mode & IFMT; 61039608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 61139608Smckusick panic("ufs_read type"); 61239608Smckusick if (uio->uio_resid == 0) 61339608Smckusick return (0); 61439608Smckusick if (uio->uio_offset < 0) 61539608Smckusick return (EINVAL); 61639608Smckusick ip->i_flag |= IACC; 61739608Smckusick fs = ip->i_fs; 61839608Smckusick do { 61939608Smckusick lbn = lblkno(fs, uio->uio_offset); 62039608Smckusick on = blkoff(fs, uio->uio_offset); 62139608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 62239608Smckusick diff = ip->i_size - uio->uio_offset; 62339608Smckusick if (diff <= 0) 62439608Smckusick return (0); 62539608Smckusick if (diff < n) 62639608Smckusick n = diff; 62739608Smckusick size = blksize(fs, ip, lbn); 62839674Smckusick rablock = lbn + 1; 62939896Smckusick if (vp->v_lastr + 1 == lbn && 63039896Smckusick lblktosize(fs, rablock) < ip->i_size) 63139896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 63239896Smckusick blksize(fs, ip, rablock), NOCRED, &bp); 63339608Smckusick else 63439674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 63539815Smckusick vp->v_lastr = lbn; 63639608Smckusick n = MIN(n, size - bp->b_resid); 63739608Smckusick if (error) { 63839608Smckusick brelse(bp); 63939608Smckusick return (error); 64039608Smckusick } 64139608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 64239608Smckusick if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size) 64339608Smckusick bp->b_flags |= B_AGE; 64439608Smckusick brelse(bp); 64539608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 64639608Smckusick return (error); 64739608Smckusick } 64839608Smckusick 64939608Smckusick /* 65039608Smckusick * Vnode op for writing. 65139608Smckusick */ 65239608Smckusick ufs_write(vp, uio, ioflag, cred) 65339608Smckusick register struct vnode *vp; 65439608Smckusick struct uio *uio; 65539608Smckusick int ioflag; 65639608Smckusick struct ucred *cred; 65739608Smckusick { 65839608Smckusick register struct inode *ip = VTOI(vp); 65939608Smckusick register struct fs *fs; 66039608Smckusick struct buf *bp; 66139608Smckusick daddr_t lbn, bn; 66239608Smckusick u_long osize; 66339608Smckusick int i, n, on, flags; 66439608Smckusick int count, size, resid, error = 0; 66539608Smckusick 66639608Smckusick if (uio->uio_rw != UIO_WRITE) 66739608Smckusick panic("ufs_write mode"); 66839608Smckusick switch (vp->v_type) { 66939608Smckusick case VREG: 67039608Smckusick if (ioflag & IO_APPEND) 67139608Smckusick uio->uio_offset = ip->i_size; 67239608Smckusick /* fall through */ 67339608Smckusick case VLNK: 67439608Smckusick break; 67539608Smckusick 67639608Smckusick case VDIR: 67739608Smckusick if ((ioflag & IO_SYNC) == 0) 67839608Smckusick panic("ufs_write nonsync dir write"); 67939608Smckusick break; 68039608Smckusick 68139608Smckusick default: 68239608Smckusick panic("ufs_write type"); 68339608Smckusick } 68439608Smckusick if (uio->uio_offset < 0) 68539608Smckusick return (EINVAL); 68639608Smckusick if (uio->uio_resid == 0) 68739608Smckusick return (0); 68839608Smckusick /* 68939608Smckusick * Maybe this should be above the vnode op call, but so long as 69039608Smckusick * file servers have no limits, i don't think it matters 69139608Smckusick */ 69239608Smckusick if (vp->v_type == VREG && 69339608Smckusick uio->uio_offset + uio->uio_resid > 69439608Smckusick u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { 69539608Smckusick psignal(u.u_procp, SIGXFSZ); 69639608Smckusick return (EFBIG); 69739608Smckusick } 69839608Smckusick resid = uio->uio_resid; 69939608Smckusick osize = ip->i_size; 70039608Smckusick fs = ip->i_fs; 70139674Smckusick flags = 0; 70239674Smckusick if (ioflag & IO_SYNC) 70339674Smckusick flags = B_SYNC; 70439608Smckusick do { 70539608Smckusick lbn = lblkno(fs, uio->uio_offset); 70639608Smckusick on = blkoff(fs, uio->uio_offset); 70739608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 70839608Smckusick if (n < fs->fs_bsize) 70939674Smckusick flags |= B_CLRBUF; 71039608Smckusick else 71139674Smckusick flags &= ~B_CLRBUF; 71239674Smckusick if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) 71339608Smckusick break; 71439674Smckusick bn = bp->b_blkno; 71539608Smckusick if (uio->uio_offset + n > ip->i_size) 71639608Smckusick ip->i_size = uio->uio_offset + n; 71739608Smckusick size = blksize(fs, ip, lbn); 71839608Smckusick count = howmany(size, CLBYTES); 71939608Smckusick for (i = 0; i < count; i++) 72039608Smckusick munhash(ip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); 72139608Smckusick n = MIN(n, size - bp->b_resid); 72239608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 72339608Smckusick if (ioflag & IO_SYNC) 72439608Smckusick (void) bwrite(bp); 72539608Smckusick else if (n + on == fs->fs_bsize) { 72639608Smckusick bp->b_flags |= B_AGE; 72739608Smckusick bawrite(bp); 72839608Smckusick } else 72939608Smckusick bdwrite(bp); 73039608Smckusick ip->i_flag |= IUPD|ICHG; 73139608Smckusick if (cred->cr_uid != 0) 73239608Smckusick ip->i_mode &= ~(ISUID|ISGID); 73339608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 73439608Smckusick if (error && (ioflag & IO_UNIT)) { 73539674Smckusick (void) itrunc(ip, osize, ioflag & IO_SYNC); 73639608Smckusick uio->uio_offset -= resid - uio->uio_resid; 73739608Smckusick uio->uio_resid = resid; 73839608Smckusick } 73939608Smckusick return (error); 74039608Smckusick } 74139608Smckusick 74239608Smckusick /* ARGSUSED */ 74337737Smckusick ufs_ioctl(vp, com, data, fflag, cred) 74437737Smckusick struct vnode *vp; 74537737Smckusick int com; 74637737Smckusick caddr_t data; 74737737Smckusick int fflag; 74837737Smckusick struct ucred *cred; 74911811Ssam { 75011811Ssam 75137737Smckusick return (ENOTTY); 75211811Ssam } 75311811Ssam 75437737Smckusick /* ARGSUSED */ 75540290Smckusick ufs_select(vp, which, fflags, cred) 75637737Smckusick struct vnode *vp; 75740290Smckusick int which, fflags; 75837737Smckusick struct ucred *cred; 75937737Smckusick { 76037737Smckusick 76137737Smckusick return (1); /* XXX */ 76237737Smckusick } 76337737Smckusick 7649167Ssam /* 76537737Smckusick * Mmap a file 76637737Smckusick * 76737737Smckusick * NB Currently unsupported. 7689167Ssam */ 76937737Smckusick /* ARGSUSED */ 77037737Smckusick ufs_mmap(vp, fflags, cred) 77137737Smckusick struct vnode *vp; 77237737Smckusick int fflags; 77337737Smckusick struct ucred *cred; 77437Sbill { 77537Sbill 77637737Smckusick return (EINVAL); 77737Sbill } 7787535Sroot 7799167Ssam /* 78037737Smckusick * Synch an open file. 7819167Ssam */ 78237737Smckusick /* ARGSUSED */ 78339597Smckusick ufs_fsync(vp, fflags, cred, waitfor) 78437737Smckusick struct vnode *vp; 78537737Smckusick int fflags; 78637737Smckusick struct ucred *cred; 78739597Smckusick int waitfor; 7887701Ssam { 78939597Smckusick struct inode *ip = VTOI(vp); 7907701Ssam 79137737Smckusick if (fflags&FWRITE) 79237737Smckusick ip->i_flag |= ICHG; 79339674Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 79439674Smckusick return (iupdat(ip, &time, &time, waitfor == MNT_WAIT)); 7957701Ssam } 7967701Ssam 7979167Ssam /* 79837737Smckusick * Seek on a file 79937737Smckusick * 80037737Smckusick * Nothing to do, so just return. 8019167Ssam */ 80237737Smckusick /* ARGSUSED */ 80337737Smckusick ufs_seek(vp, oldoff, newoff, cred) 80437737Smckusick struct vnode *vp; 80537737Smckusick off_t oldoff, newoff; 80637737Smckusick struct ucred *cred; 8077701Ssam { 8087701Ssam 80937737Smckusick return (0); 81037737Smckusick } 81137737Smckusick 81237737Smckusick /* 81337737Smckusick * ufs remove 81437737Smckusick * Hard to avoid races here, especially 81537737Smckusick * in unlinking directories. 81637737Smckusick */ 81737737Smckusick ufs_remove(ndp) 81837737Smckusick struct nameidata *ndp; 81937737Smckusick { 82037737Smckusick register struct inode *ip, *dp; 82137737Smckusick int error; 82237737Smckusick 82337737Smckusick ip = VTOI(ndp->ni_vp); 82437737Smckusick dp = VTOI(ndp->ni_dvp); 82537737Smckusick error = dirremove(ndp); 82637737Smckusick if (!error) { 82737737Smckusick ip->i_nlink--; 82837737Smckusick ip->i_flag |= ICHG; 8297701Ssam } 83037737Smckusick if (dp == ip) 83137737Smckusick vrele(ITOV(ip)); 83237737Smckusick else 83337737Smckusick iput(ip); 83437737Smckusick iput(dp); 83537737Smckusick return (error); 8367701Ssam } 8377701Ssam 8389167Ssam /* 83937737Smckusick * link vnode call 8409167Ssam */ 84137737Smckusick ufs_link(vp, ndp) 84237737Smckusick register struct vnode *vp; 84337737Smckusick register struct nameidata *ndp; 8449167Ssam { 84537737Smckusick register struct inode *ip = VTOI(vp); 84637737Smckusick int error; 8479167Ssam 84837737Smckusick if (ndp->ni_dvp != vp) 84937737Smckusick ILOCK(ip); 85037737Smckusick if (ip->i_nlink == LINK_MAX - 1) { 85137737Smckusick error = EMLINK; 85237737Smckusick goto out; 85337737Smckusick } 85437737Smckusick ip->i_nlink++; 85537737Smckusick ip->i_flag |= ICHG; 85637737Smckusick error = iupdat(ip, &time, &time, 1); 85737737Smckusick if (!error) 85837737Smckusick error = direnter(ip, ndp); 85937737Smckusick out: 86037737Smckusick if (ndp->ni_dvp != vp) 86137737Smckusick IUNLOCK(ip); 86237737Smckusick if (error) { 86337737Smckusick ip->i_nlink--; 86430598Smckusick ip->i_flag |= ICHG; 86537737Smckusick } 86637737Smckusick return (error); 8679167Ssam } 8689167Ssam 8699167Ssam /* 8709167Ssam * Rename system call. 8719167Ssam * rename("foo", "bar"); 8729167Ssam * is essentially 8739167Ssam * unlink("bar"); 8749167Ssam * link("foo", "bar"); 8759167Ssam * unlink("foo"); 8769167Ssam * but ``atomically''. Can't do full commit without saving state in the 8779167Ssam * inode on disk which isn't feasible at this time. Best we can do is 8789167Ssam * always guarantee the target exists. 8799167Ssam * 8809167Ssam * Basic algorithm is: 8819167Ssam * 8829167Ssam * 1) Bump link count on source while we're linking it to the 88337737Smckusick * target. This also ensure the inode won't be deleted out 88416776Smckusick * from underneath us while we work (it may be truncated by 88516776Smckusick * a concurrent `trunc' or `open' for creation). 8869167Ssam * 2) Link source to destination. If destination already exists, 8879167Ssam * delete it first. 88816776Smckusick * 3) Unlink source reference to inode if still around. If a 88916776Smckusick * directory was moved and the parent of the destination 8909167Ssam * is different from the source, patch the ".." entry in the 8919167Ssam * directory. 8929167Ssam */ 89337737Smckusick ufs_rename(fndp, tndp) 89437737Smckusick register struct nameidata *fndp, *tndp; 8957701Ssam { 8969167Ssam register struct inode *ip, *xp, *dp; 89716776Smckusick struct dirtemplate dirbuf; 89816776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 89910051Ssam int error = 0; 9007701Ssam 90137737Smckusick dp = VTOI(fndp->ni_dvp); 90237737Smckusick ip = VTOI(fndp->ni_vp); 90337737Smckusick ILOCK(ip); 9049167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 90537737Smckusick register struct direct *d = &fndp->ni_dent; 9069167Ssam 9079167Ssam /* 90811641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 9099167Ssam */ 91037737Smckusick if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip || 91137737Smckusick fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { 91237737Smckusick IUNLOCK(ip); 91337737Smckusick ufs_abortop(fndp); 91437737Smckusick ufs_abortop(tndp); 91537737Smckusick return (EINVAL); 9169167Ssam } 91716776Smckusick ip->i_flag |= IRENAME; 9189167Ssam oldparent = dp->i_number; 9199167Ssam doingdirectory++; 9209167Ssam } 92137737Smckusick vrele(fndp->ni_dvp); 9229167Ssam 9239167Ssam /* 9249167Ssam * 1) Bump link count while we're moving stuff 9259167Ssam * around. If we crash somewhere before 9269167Ssam * completing our work, the link count 9279167Ssam * may be wrong, but correctable. 9289167Ssam */ 9299167Ssam ip->i_nlink++; 9309167Ssam ip->i_flag |= ICHG; 93137737Smckusick error = iupdat(ip, &time, &time, 1); 93216664Smckusick IUNLOCK(ip); 9339167Ssam 9349167Ssam /* 9359167Ssam * When the target exists, both the directory 93637737Smckusick * and target vnodes are returned locked. 9379167Ssam */ 93837737Smckusick dp = VTOI(tndp->ni_dvp); 93937737Smckusick xp = NULL; 94037737Smckusick if (tndp->ni_vp) 94137737Smckusick xp = VTOI(tndp->ni_vp); 9429167Ssam /* 94311641Ssam * If ".." must be changed (ie the directory gets a new 94412816Smckusick * parent) then the source directory must not be in the 94512816Smckusick * directory heirarchy above the target, as this would 94612816Smckusick * orphan everything below the source directory. Also 94712816Smckusick * the user must have write permission in the source so 94812816Smckusick * as to be able to change "..". We must repeat the call 94912816Smckusick * to namei, as the parent directory is unlocked by the 95012816Smckusick * call to checkpath(). 95111641Ssam */ 95216776Smckusick if (oldparent != dp->i_number) 95316776Smckusick newparent = dp->i_number; 95416776Smckusick if (doingdirectory && newparent) { 955*41312Smckusick if (error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred)) 95612816Smckusick goto bad; 95737737Smckusick tndp->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 95812816Smckusick do { 95937737Smckusick dp = VTOI(tndp->ni_dvp); 96012816Smckusick if (xp != NULL) 96138069Smckusick iput(xp); 96237737Smckusick if (error = checkpath(ip, dp, tndp->ni_cred)) 96312816Smckusick goto out; 96437737Smckusick if (error = namei(tndp)) 96512816Smckusick goto out; 96637737Smckusick xp = NULL; 96737737Smckusick if (tndp->ni_vp) 96837737Smckusick xp = VTOI(tndp->ni_vp); 96937737Smckusick } while (dp != VTOI(tndp->ni_dvp)); 97012816Smckusick } 97111641Ssam /* 9729167Ssam * 2) If target doesn't exist, link the target 9739167Ssam * to the source and unlink the source. 9749167Ssam * Otherwise, rewrite the target directory 9759167Ssam * entry to reference the source inode and 9769167Ssam * expunge the original entry's existence. 9779167Ssam */ 9789167Ssam if (xp == NULL) { 97937737Smckusick if (dp->i_dev != ip->i_dev) 98037737Smckusick panic("rename: EXDEV"); 9819167Ssam /* 98216776Smckusick * Account for ".." in new directory. 98316776Smckusick * When source and destination have the same 98416776Smckusick * parent we don't fool with the link count. 9859167Ssam */ 98616776Smckusick if (doingdirectory && newparent) { 9879167Ssam dp->i_nlink++; 9889167Ssam dp->i_flag |= ICHG; 98937737Smckusick error = iupdat(dp, &time, &time, 1); 9909167Ssam } 99137737Smckusick if (error = direnter(ip, tndp)) 9929167Ssam goto out; 9939167Ssam } else { 99437737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 99537737Smckusick panic("rename: EXDEV"); 9969167Ssam /* 99710590Ssam * Short circuit rename(foo, foo). 99810590Ssam */ 99910590Ssam if (xp->i_number == ip->i_number) 100037737Smckusick panic("rename: same file"); 100110590Ssam /* 100224433Sbloom * If the parent directory is "sticky", then the user must 100324433Sbloom * own the parent directory, or the destination of the rename, 100424433Sbloom * otherwise the destination may not be changed (except by 100524433Sbloom * root). This implements append-only directories. 100624433Sbloom */ 100737737Smckusick if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && 100837737Smckusick tndp->ni_cred->cr_uid != dp->i_uid && 100937737Smckusick xp->i_uid != tndp->ni_cred->cr_uid) { 101024433Sbloom error = EPERM; 101124433Sbloom goto bad; 101224433Sbloom } 101324433Sbloom /* 101410051Ssam * Target must be empty if a directory 101510051Ssam * and have no links to it. 10169167Ssam * Also, insure source and target are 10179167Ssam * compatible (both directories, or both 10189167Ssam * not directories). 10199167Ssam */ 10209167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 102137737Smckusick if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 102237737Smckusick xp->i_nlink > 2) { 102310051Ssam error = ENOTEMPTY; 10249167Ssam goto bad; 10259167Ssam } 10269167Ssam if (!doingdirectory) { 102710051Ssam error = ENOTDIR; 10289167Ssam goto bad; 10299167Ssam } 103037737Smckusick cache_purge(ITOV(dp)); 10319167Ssam } else if (doingdirectory) { 103210051Ssam error = EISDIR; 10339167Ssam goto bad; 10349167Ssam } 103537737Smckusick if (error = dirrewrite(dp, ip, tndp)) 103637737Smckusick goto bad; 103737737Smckusick vput(ITOV(dp)); 10389167Ssam /* 103910051Ssam * Adjust the link count of the target to 104010051Ssam * reflect the dirrewrite above. If this is 104110051Ssam * a directory it is empty and there are 104210051Ssam * no links to it, so we can squash the inode and 104310051Ssam * any space associated with it. We disallowed 104410051Ssam * renaming over top of a directory with links to 104516776Smckusick * it above, as the remaining link would point to 104616776Smckusick * a directory without "." or ".." entries. 10479167Ssam */ 104810051Ssam xp->i_nlink--; 10499167Ssam if (doingdirectory) { 105010051Ssam if (--xp->i_nlink != 0) 105110051Ssam panic("rename: linked directory"); 105239674Smckusick error = itrunc(xp, (u_long)0, IO_SYNC); 105310051Ssam } 10549167Ssam xp->i_flag |= ICHG; 105538398Smckusick iput(xp); 105610246Ssam xp = NULL; 10579167Ssam } 10589167Ssam 10599167Ssam /* 10609167Ssam * 3) Unlink the source. 10619167Ssam */ 106237737Smckusick fndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 106337737Smckusick (void)namei(fndp); 106437737Smckusick if (fndp->ni_vp != NULL) { 106537737Smckusick xp = VTOI(fndp->ni_vp); 106637737Smckusick dp = VTOI(fndp->ni_dvp); 106737737Smckusick } else { 106838069Smckusick if (fndp->ni_dvp != NULL) 106938069Smckusick vput(fndp->ni_dvp); 107037737Smckusick xp = NULL; 107117758Smckusick dp = NULL; 107237737Smckusick } 10739167Ssam /* 107437737Smckusick * Ensure that the directory entry still exists and has not 107516776Smckusick * changed while the new name has been entered. If the source is 107616776Smckusick * a file then the entry may have been unlinked or renamed. In 107716776Smckusick * either case there is no further work to be done. If the source 107816776Smckusick * is a directory then it cannot have been rmdir'ed; its link 107916776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 108037737Smckusick * The IRENAME flag ensures that it cannot be moved by another 108116776Smckusick * rename. 10829167Ssam */ 108317758Smckusick if (xp != ip) { 108416776Smckusick if (doingdirectory) 108517758Smckusick panic("rename: lost dir entry"); 108616776Smckusick } else { 10879167Ssam /* 108816776Smckusick * If the source is a directory with a 108916776Smckusick * new parent, the link count of the old 109016776Smckusick * parent directory must be decremented 109116776Smckusick * and ".." set to point to the new parent. 10929167Ssam */ 109316776Smckusick if (doingdirectory && newparent) { 10949167Ssam dp->i_nlink--; 10959167Ssam dp->i_flag |= ICHG; 109639597Smckusick error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, 109737737Smckusick sizeof (struct dirtemplate), (off_t)0, 109839597Smckusick UIO_SYSSPACE, IO_NODELOCKED, 109939597Smckusick tndp->ni_cred, (int *)0); 110016776Smckusick if (error == 0) { 110116776Smckusick if (dirbuf.dotdot_namlen != 2 || 110216776Smckusick dirbuf.dotdot_name[0] != '.' || 110316776Smckusick dirbuf.dotdot_name[1] != '.') { 110439610Smckusick dirbad(xp, 12, "rename: mangled dir"); 110516776Smckusick } else { 110616776Smckusick dirbuf.dotdot_ino = newparent; 110739597Smckusick (void) vn_rdwr(UIO_WRITE, ITOV(xp), 110816776Smckusick (caddr_t)&dirbuf, 110916776Smckusick sizeof (struct dirtemplate), 111037740Smckusick (off_t)0, UIO_SYSSPACE, 111139597Smckusick IO_NODELOCKED|IO_SYNC, 111237737Smckusick tndp->ni_cred, (int *)0); 111337737Smckusick cache_purge(ITOV(dp)); 111416776Smckusick } 111516776Smckusick } 11169167Ssam } 111737737Smckusick error = dirremove(fndp); 111837737Smckusick if (!error) { 111916776Smckusick xp->i_nlink--; 112016776Smckusick xp->i_flag |= ICHG; 11219167Ssam } 112216776Smckusick xp->i_flag &= ~IRENAME; 11239167Ssam } 11249167Ssam if (dp) 112537737Smckusick vput(ITOV(dp)); 112616776Smckusick if (xp) 112737737Smckusick vput(ITOV(xp)); 112837737Smckusick vrele(ITOV(ip)); 112937737Smckusick return (error); 11309167Ssam 11319167Ssam bad: 11329167Ssam if (xp) 113337737Smckusick vput(ITOV(xp)); 113437737Smckusick vput(ITOV(dp)); 11359167Ssam out: 11369167Ssam ip->i_nlink--; 11379167Ssam ip->i_flag |= ICHG; 113837737Smckusick vrele(ITOV(ip)); 113937737Smckusick return (error); 11407701Ssam } 11417701Ssam 11427535Sroot /* 114312756Ssam * A virgin directory (no blushing please). 114412756Ssam */ 114512756Ssam struct dirtemplate mastertemplate = { 114612756Ssam 0, 12, 1, ".", 114712756Ssam 0, DIRBLKSIZ - 12, 2, ".." 114812756Ssam }; 114912756Ssam 115012756Ssam /* 115112756Ssam * Mkdir system call 115212756Ssam */ 115337737Smckusick ufs_mkdir(ndp, vap) 115437737Smckusick struct nameidata *ndp; 115537737Smckusick struct vattr *vap; 115612756Ssam { 115712756Ssam register struct inode *ip, *dp; 115837737Smckusick struct inode *tip; 115937737Smckusick struct vnode *dvp; 116012756Ssam struct dirtemplate dirtemplate; 116137737Smckusick int error; 116237737Smckusick int dmode; 116312756Ssam 116437737Smckusick dvp = ndp->ni_dvp; 116537737Smckusick dp = VTOI(dvp); 116637737Smckusick dmode = vap->va_mode&0777; 116737737Smckusick dmode |= IFDIR; 116812756Ssam /* 116912756Ssam * Must simulate part of maknode here 117012756Ssam * in order to acquire the inode, but 117112756Ssam * not have it entered in the parent 117212756Ssam * directory. The entry is made later 117312756Ssam * after writing "." and ".." entries out. 117412756Ssam */ 1175*41312Smckusick if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { 117612756Ssam iput(dp); 117737737Smckusick return (error); 117812756Ssam } 117937737Smckusick ip = tip; 1180*41312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 1181*41312Smckusick ip->i_gid = dp->i_gid; 118212756Ssam #ifdef QUOTA 1183*41312Smckusick if ((error = getinoquota(ip)) || 1184*41312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 1185*41312Smckusick ifree(ip, ip->i_number, dmode); 1186*41312Smckusick iput(ip); 1187*41312Smckusick iput(dp); 1188*41312Smckusick return (error); 1189*41312Smckusick } 119012756Ssam #endif 119112756Ssam ip->i_flag |= IACC|IUPD|ICHG; 119237737Smckusick ip->i_mode = dmode; 119337737Smckusick ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ 119412756Ssam ip->i_nlink = 2; 119537737Smckusick error = iupdat(ip, &time, &time, 1); 119612756Ssam 119712756Ssam /* 119812756Ssam * Bump link count in parent directory 119912756Ssam * to reflect work done below. Should 120012756Ssam * be done before reference is created 120112756Ssam * so reparation is possible if we crash. 120212756Ssam */ 120312756Ssam dp->i_nlink++; 120412756Ssam dp->i_flag |= ICHG; 120537737Smckusick error = iupdat(dp, &time, &time, 1); 120612756Ssam 120712756Ssam /* 120812756Ssam * Initialize directory with "." 120912756Ssam * and ".." from static template. 121012756Ssam */ 121112756Ssam dirtemplate = mastertemplate; 121212756Ssam dirtemplate.dot_ino = ip->i_number; 121312756Ssam dirtemplate.dotdot_ino = dp->i_number; 121439597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, 121537737Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 121639597Smckusick IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0); 121737737Smckusick if (error) { 121812756Ssam dp->i_nlink--; 121912756Ssam dp->i_flag |= ICHG; 122012756Ssam goto bad; 122112756Ssam } 122237737Smckusick if (DIRBLKSIZ > dp->i_fs->fs_fsize) 122337737Smckusick panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ 122418103Smckusick else 122518103Smckusick ip->i_size = DIRBLKSIZ; 122612756Ssam /* 122712756Ssam * Directory all set up, now 122812756Ssam * install the entry for it in 122912756Ssam * the parent directory. 123012756Ssam */ 123137737Smckusick error = direnter(ip, ndp); 123212756Ssam dp = NULL; 123337737Smckusick if (error) { 123416694Smckusick ndp->ni_nameiop = LOOKUP | NOCACHE; 123537737Smckusick error = namei(ndp); 123637737Smckusick if (!error) { 123737737Smckusick dp = VTOI(ndp->ni_vp); 123812756Ssam dp->i_nlink--; 123912756Ssam dp->i_flag |= ICHG; 124012756Ssam } 124112756Ssam } 124212756Ssam bad: 124312756Ssam /* 124412756Ssam * No need to do an explicit itrunc here, 124537737Smckusick * vrele will do this for us because we set 124612756Ssam * the link count to 0. 124712756Ssam */ 124837737Smckusick if (error) { 124912756Ssam ip->i_nlink = 0; 125012756Ssam ip->i_flag |= ICHG; 125138144Smckusick iput(ip); 125238144Smckusick } else 125338144Smckusick ndp->ni_vp = ITOV(ip); 125412756Ssam if (dp) 125512756Ssam iput(dp); 125637737Smckusick return (error); 125712756Ssam } 125812756Ssam 125912756Ssam /* 126012756Ssam * Rmdir system call. 126112756Ssam */ 126237737Smckusick ufs_rmdir(ndp) 126337737Smckusick register struct nameidata *ndp; 126412756Ssam { 126512756Ssam register struct inode *ip, *dp; 126637737Smckusick int error = 0; 126712756Ssam 126837737Smckusick ip = VTOI(ndp->ni_vp); 126937737Smckusick dp = VTOI(ndp->ni_dvp); 127012756Ssam /* 127112756Ssam * No rmdir "." please. 127212756Ssam */ 127312756Ssam if (dp == ip) { 127437737Smckusick vrele(ITOV(dp)); 127512756Ssam iput(ip); 127637737Smckusick return (EINVAL); 127712756Ssam } 127812756Ssam /* 127912756Ssam * Verify the directory is empty (and valid). 128012756Ssam * (Rmdir ".." won't be valid since 128112756Ssam * ".." will contain a reference to 128212756Ssam * the current directory and thus be 128312756Ssam * non-empty.) 128412756Ssam */ 128537737Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { 128637737Smckusick error = ENOTEMPTY; 128712756Ssam goto out; 128812756Ssam } 128912756Ssam /* 129012756Ssam * Delete reference to directory before purging 129112756Ssam * inode. If we crash in between, the directory 129212756Ssam * will be reattached to lost+found, 129312756Ssam */ 129437737Smckusick if (error = dirremove(ndp)) 129512756Ssam goto out; 129612756Ssam dp->i_nlink--; 129712756Ssam dp->i_flag |= ICHG; 129837737Smckusick cache_purge(ITOV(dp)); 129912756Ssam iput(dp); 130037737Smckusick ndp->ni_dvp = NULL; 130112756Ssam /* 130212756Ssam * Truncate inode. The only stuff left 130312756Ssam * in the directory is "." and "..". The 130412756Ssam * "." reference is inconsequential since 130512756Ssam * we're quashing it. The ".." reference 130612756Ssam * has already been adjusted above. We've 130712756Ssam * removed the "." reference and the reference 130812756Ssam * in the parent directory, but there may be 130912756Ssam * other hard links so decrement by 2 and 131012756Ssam * worry about them later. 131112756Ssam */ 131212756Ssam ip->i_nlink -= 2; 131339674Smckusick error = itrunc(ip, (u_long)0, IO_SYNC); 131437737Smckusick cache_purge(ITOV(ip)); 131512756Ssam out: 131637737Smckusick if (ndp->ni_dvp) 131712756Ssam iput(dp); 131812756Ssam iput(ip); 131937737Smckusick return (error); 132012756Ssam } 132112756Ssam 132237737Smckusick /* 132337737Smckusick * symlink -- make a symbolic link 132437737Smckusick */ 132537737Smckusick ufs_symlink(ndp, vap, target) 132637737Smckusick struct nameidata *ndp; 132737737Smckusick struct vattr *vap; 132837737Smckusick char *target; 132912756Ssam { 133037737Smckusick struct inode *ip; 133137737Smckusick int error; 133212756Ssam 133337737Smckusick error = maknode(IFLNK | vap->va_mode, ndp, &ip); 133437737Smckusick if (error) 133537737Smckusick return (error); 133639597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, 133739597Smckusick UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0); 133837737Smckusick iput(ip); 133937737Smckusick return (error); 134037737Smckusick } 134137737Smckusick 134237737Smckusick /* 134337737Smckusick * Vnode op for read and write 134437737Smckusick */ 134540345Smckusick ufs_readdir(vp, uio, cred, eofflagp) 134637737Smckusick struct vnode *vp; 134737737Smckusick register struct uio *uio; 134837737Smckusick struct ucred *cred; 134940345Smckusick int *eofflagp; 135037737Smckusick { 135139597Smckusick int count, lost, error; 135237737Smckusick 135337737Smckusick count = uio->uio_resid; 135437737Smckusick count &= ~(DIRBLKSIZ - 1); 135539597Smckusick lost = uio->uio_resid - count; 135639597Smckusick if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) 135737737Smckusick return (EINVAL); 135837737Smckusick uio->uio_resid = count; 135937737Smckusick uio->uio_iov->iov_len = count; 136039597Smckusick error = ufs_read(vp, uio, 0, cred); 136139597Smckusick uio->uio_resid += lost; 136240345Smckusick if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) 136340345Smckusick *eofflagp = 1; 136440345Smckusick else 136540345Smckusick *eofflagp = 0; 136637737Smckusick return (error); 136737737Smckusick } 136837737Smckusick 136937737Smckusick /* 137037737Smckusick * Return target name of a symbolic link 137137737Smckusick */ 137237737Smckusick ufs_readlink(vp, uiop, cred) 137337737Smckusick struct vnode *vp; 137437737Smckusick struct uio *uiop; 137537737Smckusick struct ucred *cred; 137637737Smckusick { 137737737Smckusick 137839597Smckusick return (ufs_read(vp, uiop, 0, cred)); 137937737Smckusick } 138037737Smckusick 138137737Smckusick /* 138237737Smckusick * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 138337737Smckusick * done. Iff ni_vp/ni_dvp not null and locked, unlock. 138437737Smckusick */ 138537737Smckusick ufs_abortop(ndp) 138637737Smckusick register struct nameidata *ndp; 138737737Smckusick { 138837737Smckusick 138940107Smckusick if (ndp->ni_dvp) { 139040107Smckusick if (VOP_ISLOCKED(ndp->ni_dvp)) 139140107Smckusick VOP_UNLOCK(ndp->ni_dvp); 139240107Smckusick vrele(ndp->ni_dvp); 139340107Smckusick } 139437737Smckusick if (ndp->ni_vp) { 139540107Smckusick if (VOP_ISLOCKED(ndp->ni_vp)) 139640107Smckusick VOP_UNLOCK(ndp->ni_vp); 139737737Smckusick vrele(ndp->ni_vp); 139812756Ssam } 139937737Smckusick return; 140012756Ssam } 140112756Ssam 140239909Smckusick /* 140339909Smckusick * Lock an inode. 140439909Smckusick */ 140537737Smckusick ufs_lock(vp) 140637737Smckusick struct vnode *vp; 140737737Smckusick { 140837737Smckusick register struct inode *ip = VTOI(vp); 140937737Smckusick 141037737Smckusick ILOCK(ip); 141137737Smckusick return (0); 141237737Smckusick } 141337737Smckusick 141439909Smckusick /* 141539909Smckusick * Unlock an inode. 141639909Smckusick */ 141737737Smckusick ufs_unlock(vp) 141837737Smckusick struct vnode *vp; 141937737Smckusick { 142037737Smckusick register struct inode *ip = VTOI(vp); 142137737Smckusick 142237737Smckusick if (!(ip->i_flag & ILOCKED)) 142337737Smckusick panic("ufs_unlock NOT LOCKED"); 142437737Smckusick IUNLOCK(ip); 142537737Smckusick return (0); 142637737Smckusick } 142737737Smckusick 142812756Ssam /* 142939909Smckusick * Check for a locked inode. 143039909Smckusick */ 143139909Smckusick ufs_islocked(vp) 143239909Smckusick struct vnode *vp; 143339909Smckusick { 143439909Smckusick 143539909Smckusick if (VTOI(vp)->i_flag & ILOCKED) 143639909Smckusick return (1); 143739909Smckusick return (0); 143839909Smckusick } 143939909Smckusick 144039909Smckusick /* 144137737Smckusick * Get access to bmap 144212756Ssam */ 144337737Smckusick ufs_bmap(vp, bn, vpp, bnp) 144437737Smckusick struct vnode *vp; 144537737Smckusick daddr_t bn; 144637737Smckusick struct vnode **vpp; 144737737Smckusick daddr_t *bnp; 144812756Ssam { 144937737Smckusick struct inode *ip = VTOI(vp); 145012756Ssam 145137737Smckusick if (vpp != NULL) 145237737Smckusick *vpp = ip->i_devvp; 145337737Smckusick if (bnp == NULL) 145437737Smckusick return (0); 145537737Smckusick return (bmap(ip, bn, bnp, (daddr_t *)0, (int *)0)); 145612756Ssam } 145737737Smckusick 145837737Smckusick /* 145937737Smckusick * Just call the device strategy routine 146037737Smckusick */ 146139674Smckusick int checkoverlap = 1; 146239674Smckusick 146337737Smckusick ufs_strategy(bp) 146437737Smckusick register struct buf *bp; 146537737Smckusick { 146639674Smckusick register struct inode *ip = VTOI(bp->b_vp); 146739674Smckusick register struct buf *ep; 146839674Smckusick struct vnode *vp; 146939674Smckusick struct buf *ebp; 147039674Smckusick daddr_t start, last; 147139674Smckusick int error; 147239674Smckusick 147339674Smckusick if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 147439674Smckusick panic("ufs_strategy: spec"); 147539674Smckusick if (bp->b_blkno == bp->b_lblkno) { 147639674Smckusick if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno)) 147739674Smckusick return (error); 147839896Smckusick if ((long)bp->b_blkno == -1) 147939674Smckusick clrbuf(bp); 148039674Smckusick } 148139896Smckusick if ((long)bp->b_blkno == -1) { 148239896Smckusick biodone(bp); 148339674Smckusick return (0); 148439896Smckusick } 148539674Smckusick if (checkoverlap) { 148639674Smckusick ebp = &buf[nbuf]; 148739674Smckusick start = bp->b_blkno; 148839674Smckusick last = start + btodb(bp->b_bcount) - 1; 148939674Smckusick for (ep = buf; ep < ebp; ep++) { 149039674Smckusick if (ep == bp || (ep->b_flags & B_INVAL) || 149139674Smckusick ep->b_vp == (struct vnode *)0) 149239674Smckusick continue; 149339674Smckusick if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0)) 149439674Smckusick continue; 149539674Smckusick if (vp != ip->i_devvp) 149639674Smckusick continue; 149739674Smckusick /* look for overlap */ 149839674Smckusick if (ep->b_bcount == 0 || ep->b_blkno > last || 149939674Smckusick ep->b_blkno + btodb(ep->b_bcount) <= start) 150039674Smckusick continue; 150139896Smckusick vprint("Disk overlap", vp); 150239896Smckusick printf("\tstart %d, end %d overlap start %d, end %d\n", 150339896Smckusick start, last, ep->b_blkno, 150439896Smckusick ep->b_blkno + btodb(ep->b_bcount) - 1); 150539674Smckusick } 150639674Smckusick } 150739674Smckusick vp = ip->i_devvp; 150839674Smckusick bp->b_dev = vp->v_rdev; 150939674Smckusick (*(vp->v_op->vn_strategy))(bp); 151037737Smckusick return (0); 151137737Smckusick } 151237737Smckusick 151337737Smckusick /* 151439674Smckusick * Print out the contents of an inode. 151539674Smckusick */ 151639674Smckusick ufs_print(vp) 151739674Smckusick struct vnode *vp; 151839674Smckusick { 151939674Smckusick register struct inode *ip = VTOI(vp); 152039674Smckusick 152140293Smckusick printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number, 152240293Smckusick major(ip->i_dev), minor(ip->i_dev)); 152340293Smckusick #ifdef FIFO 152440293Smckusick if (vp->v_type == VFIFO) 152540293Smckusick fifo_printinfo(vp); 152640293Smckusick #endif /* FIFO */ 152740293Smckusick printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : ""); 152839900Smckusick if (ip->i_spare0 == 0) 152939900Smckusick return; 153039900Smckusick printf("\towner pid %d", ip->i_spare0); 153139900Smckusick if (ip->i_spare1) 153239900Smckusick printf(" waiting pid %d", ip->i_spare1); 153339900Smckusick printf("\n"); 153439674Smckusick } 153539674Smckusick 153639674Smckusick /* 153739628Smckusick * Read wrapper for special devices. 153839628Smckusick */ 153939628Smckusick ufsspec_read(vp, uio, ioflag, cred) 154039628Smckusick struct vnode *vp; 154139628Smckusick struct uio *uio; 154239628Smckusick int ioflag; 154339628Smckusick struct ucred *cred; 154439628Smckusick { 154539628Smckusick 154639628Smckusick /* 154739628Smckusick * Set access flag. 154839628Smckusick */ 154939628Smckusick VTOI(vp)->i_flag |= IACC; 155039628Smckusick return (spec_read(vp, uio, ioflag, cred)); 155139628Smckusick } 155239628Smckusick 155339628Smckusick /* 155439628Smckusick * Write wrapper for special devices. 155539628Smckusick */ 155639628Smckusick ufsspec_write(vp, uio, ioflag, cred) 155739628Smckusick struct vnode *vp; 155839628Smckusick struct uio *uio; 155939628Smckusick int ioflag; 156039628Smckusick struct ucred *cred; 156139628Smckusick { 156239628Smckusick 156339628Smckusick /* 156439628Smckusick * Set update and change flags. 156539628Smckusick */ 156639628Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 156739628Smckusick return (spec_write(vp, uio, ioflag, cred)); 156839628Smckusick } 156939628Smckusick 157039628Smckusick /* 157139628Smckusick * Close wrapper for special devices. 157239628Smckusick * 157339628Smckusick * Update the times on the inode then do device close. 157439628Smckusick */ 157539628Smckusick ufsspec_close(vp, fflag, cred) 157639628Smckusick struct vnode *vp; 157739628Smckusick int fflag; 157839628Smckusick struct ucred *cred; 157939628Smckusick { 158039628Smckusick register struct inode *ip = VTOI(vp); 158139628Smckusick 158239815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 158339628Smckusick ITIMES(ip, &time, &time); 158439628Smckusick return (spec_close(vp, fflag, cred)); 158539628Smckusick } 158639628Smckusick 158740290Smckusick #ifdef FIFO 158839628Smckusick /* 158940290Smckusick * Read wrapper for fifo's 159040290Smckusick */ 159140290Smckusick ufsfifo_read(vp, uio, ioflag, cred) 159240290Smckusick struct vnode *vp; 159340290Smckusick struct uio *uio; 159440290Smckusick int ioflag; 159540290Smckusick struct ucred *cred; 159640290Smckusick { 159740290Smckusick 159840290Smckusick /* 159940290Smckusick * Set access flag. 160040290Smckusick */ 160140290Smckusick VTOI(vp)->i_flag |= IACC; 160240290Smckusick return (fifo_read(vp, uio, ioflag, cred)); 160340290Smckusick } 160440290Smckusick 160540290Smckusick /* 160640290Smckusick * Write wrapper for fifo's. 160740290Smckusick */ 160840290Smckusick ufsfifo_write(vp, uio, ioflag, cred) 160940290Smckusick struct vnode *vp; 161040290Smckusick struct uio *uio; 161140290Smckusick int ioflag; 161240290Smckusick struct ucred *cred; 161340290Smckusick { 161440290Smckusick 161540290Smckusick /* 161640290Smckusick * Set update and change flags. 161740290Smckusick */ 161840290Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 161940290Smckusick return (fifo_write(vp, uio, ioflag, cred)); 162040290Smckusick } 162140290Smckusick 162240290Smckusick /* 162340290Smckusick * Close wrapper for fifo's. 162440290Smckusick * 162540290Smckusick * Update the times on the inode then do device close. 162640290Smckusick */ 162740290Smckusick ufsfifo_close(vp, fflag, cred) 162840290Smckusick struct vnode *vp; 162940290Smckusick int fflag; 163040290Smckusick struct ucred *cred; 163140290Smckusick { 163240290Smckusick register struct inode *ip = VTOI(vp); 163340290Smckusick 163440290Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 163540290Smckusick ITIMES(ip, &time, &time); 163640290Smckusick return (fifo_close(vp, fflag, cred)); 163740290Smckusick } 163840290Smckusick #endif /* FIFO */ 163940290Smckusick 164040290Smckusick /* 164137737Smckusick * Make a new file. 164237737Smckusick */ 164337737Smckusick maknode(mode, ndp, ipp) 164437737Smckusick int mode; 164537737Smckusick register struct nameidata *ndp; 164637737Smckusick struct inode **ipp; 164737737Smckusick { 164837737Smckusick register struct inode *ip; 164937737Smckusick struct inode *tip; 165037737Smckusick register struct inode *pdir = VTOI(ndp->ni_dvp); 165137737Smckusick ino_t ipref; 165237737Smckusick int error; 165337737Smckusick 165437737Smckusick *ipp = 0; 1655*41312Smckusick if ((mode & IFMT) == 0) 1656*41312Smckusick mode |= IFREG; 165737737Smckusick if ((mode & IFMT) == IFDIR) 165837737Smckusick ipref = dirpref(pdir->i_fs); 165937737Smckusick else 166037737Smckusick ipref = pdir->i_number; 1661*41312Smckusick if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { 166237737Smckusick iput(pdir); 166337737Smckusick return (error); 166437737Smckusick } 166537737Smckusick ip = tip; 1666*41312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 1667*41312Smckusick ip->i_gid = pdir->i_gid; 166837737Smckusick #ifdef QUOTA 1669*41312Smckusick if ((error = getinoquota(ip)) || 1670*41312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 1671*41312Smckusick ifree(ip, ip->i_number, mode); 1672*41312Smckusick iput(ip); 1673*41312Smckusick iput(pdir); 1674*41312Smckusick return (error); 1675*41312Smckusick } 167637737Smckusick #endif 167737737Smckusick ip->i_flag |= IACC|IUPD|ICHG; 167837737Smckusick ip->i_mode = mode; 167937737Smckusick ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ 168037737Smckusick ip->i_nlink = 1; 168137737Smckusick if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && 168237737Smckusick suser(ndp->ni_cred, NULL)) 168337737Smckusick ip->i_mode &= ~ISGID; 168437737Smckusick 168537737Smckusick /* 168637737Smckusick * Make sure inode goes to disk before directory entry. 168737737Smckusick */ 1688*41312Smckusick if (error = iupdat(ip, &time, &time, 1)) 1689*41312Smckusick goto bad; 1690*41312Smckusick if (error = direnter(ip, ndp)) { 1691*41312Smckusick pdir = NULL; 1692*41312Smckusick goto bad; 169337737Smckusick } 169437737Smckusick *ipp = ip; 169537737Smckusick return (0); 1696*41312Smckusick 1697*41312Smckusick bad: 1698*41312Smckusick /* 1699*41312Smckusick * Write error occurred trying to update the inode 1700*41312Smckusick * or the directory so must deallocate the inode. 1701*41312Smckusick */ 1702*41312Smckusick if (pdir) 1703*41312Smckusick iput(pdir); 1704*41312Smckusick ip->i_nlink = 0; 1705*41312Smckusick ip->i_flag |= ICHG; 1706*41312Smckusick iput(ip); 1707*41312Smckusick return (error); 170837737Smckusick } 1709