123405Smckusick /* 237737Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337737Smckusick * All rights reserved. 423405Smckusick * 5*44539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*44539Sbostic * @(#)lfs_vnops.c 7.45 (Berkeley) 06/28/90 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 1217101Sbloom #include "user.h" 1317101Sbloom #include "kernel.h" 1417101Sbloom #include "file.h" 1517101Sbloom #include "stat.h" 1617101Sbloom #include "buf.h" 1717101Sbloom #include "proc.h" 1817101Sbloom #include "socket.h" 1917101Sbloom #include "socketvar.h" 2037737Smckusick #include "conf.h" 2117101Sbloom #include "mount.h" 2237737Smckusick #include "vnode.h" 2340653Smckusick #include "specdev.h" 2441312Smckusick #include "../ufs/quota.h" 2537737Smckusick #include "../ufs/inode.h" 2637737Smckusick #include "../ufs/fs.h" 2737Sbill 289167Ssam /* 2937737Smckusick * Global vfs data structures for ufs 309167Ssam */ 316254Sroot 3237737Smckusick int ufs_lookup(), 3337737Smckusick ufs_create(), 3437737Smckusick ufs_mknod(), 3537737Smckusick ufs_open(), 3637737Smckusick ufs_close(), 3737737Smckusick ufs_access(), 3837737Smckusick ufs_getattr(), 3937737Smckusick ufs_setattr(), 4037737Smckusick ufs_read(), 4137737Smckusick ufs_write(), 4237737Smckusick ufs_ioctl(), 4337737Smckusick ufs_select(), 4437737Smckusick ufs_mmap(), 4537737Smckusick ufs_fsync(), 4637737Smckusick ufs_seek(), 4737737Smckusick ufs_remove(), 4837737Smckusick ufs_link(), 4937737Smckusick ufs_rename(), 5037737Smckusick ufs_mkdir(), 5137737Smckusick ufs_rmdir(), 5237737Smckusick ufs_symlink(), 5337737Smckusick ufs_readdir(), 5437737Smckusick ufs_readlink(), 5537737Smckusick ufs_abortop(), 5637737Smckusick ufs_inactive(), 5739391Smckusick ufs_reclaim(), 5837737Smckusick ufs_lock(), 5937737Smckusick ufs_unlock(), 6037737Smckusick ufs_bmap(), 6139674Smckusick ufs_strategy(), 6239909Smckusick ufs_print(), 6339909Smckusick ufs_islocked(); 646254Sroot 6537737Smckusick struct vnodeops ufs_vnodeops = { 6639674Smckusick ufs_lookup, /* lookup */ 6739674Smckusick ufs_create, /* create */ 6839674Smckusick ufs_mknod, /* mknod */ 6939674Smckusick ufs_open, /* open */ 7039674Smckusick ufs_close, /* close */ 7139674Smckusick ufs_access, /* access */ 7239674Smckusick ufs_getattr, /* getattr */ 7339674Smckusick ufs_setattr, /* setattr */ 7439674Smckusick ufs_read, /* read */ 7539674Smckusick ufs_write, /* write */ 7639674Smckusick ufs_ioctl, /* ioctl */ 7739674Smckusick ufs_select, /* select */ 7839674Smckusick ufs_mmap, /* mmap */ 7939674Smckusick ufs_fsync, /* fsync */ 8039674Smckusick ufs_seek, /* seek */ 8139674Smckusick ufs_remove, /* remove */ 8239674Smckusick ufs_link, /* link */ 8339674Smckusick ufs_rename, /* rename */ 8439674Smckusick ufs_mkdir, /* mkdir */ 8539674Smckusick ufs_rmdir, /* rmdir */ 8639674Smckusick ufs_symlink, /* symlink */ 8739674Smckusick ufs_readdir, /* readdir */ 8839674Smckusick ufs_readlink, /* readlink */ 8939674Smckusick ufs_abortop, /* abortop */ 9039674Smckusick ufs_inactive, /* inactive */ 9139674Smckusick ufs_reclaim, /* reclaim */ 9239674Smckusick ufs_lock, /* lock */ 9339674Smckusick ufs_unlock, /* unlock */ 9439674Smckusick ufs_bmap, /* bmap */ 9539674Smckusick ufs_strategy, /* strategy */ 9639674Smckusick ufs_print, /* print */ 9739909Smckusick ufs_islocked, /* islocked */ 9837737Smckusick }; 996254Sroot 10039435Smckusick int spec_lookup(), 10139435Smckusick spec_open(), 10239628Smckusick ufsspec_read(), 10339628Smckusick ufsspec_write(), 10439435Smckusick spec_strategy(), 10539674Smckusick spec_bmap(), 10639435Smckusick spec_ioctl(), 10739435Smckusick spec_select(), 10839628Smckusick ufsspec_close(), 10939435Smckusick spec_badop(), 11039435Smckusick spec_nullop(); 11139435Smckusick 11239435Smckusick struct vnodeops spec_inodeops = { 11339597Smckusick spec_lookup, /* lookup */ 11439597Smckusick spec_badop, /* create */ 11539597Smckusick spec_badop, /* mknod */ 11639597Smckusick spec_open, /* open */ 11739628Smckusick ufsspec_close, /* close */ 11839597Smckusick ufs_access, /* access */ 11939597Smckusick ufs_getattr, /* getattr */ 12039597Smckusick ufs_setattr, /* setattr */ 12139628Smckusick ufsspec_read, /* read */ 12239628Smckusick ufsspec_write, /* write */ 12339597Smckusick spec_ioctl, /* ioctl */ 12439597Smckusick spec_select, /* select */ 12539597Smckusick spec_badop, /* mmap */ 12639597Smckusick spec_nullop, /* fsync */ 12739597Smckusick spec_badop, /* seek */ 12839597Smckusick spec_badop, /* remove */ 12939597Smckusick spec_badop, /* link */ 13039597Smckusick spec_badop, /* rename */ 13139597Smckusick spec_badop, /* mkdir */ 13239597Smckusick spec_badop, /* rmdir */ 13339597Smckusick spec_badop, /* symlink */ 13439597Smckusick spec_badop, /* readdir */ 13539597Smckusick spec_badop, /* readlink */ 13639597Smckusick spec_badop, /* abortop */ 13739597Smckusick ufs_inactive, /* inactive */ 13839597Smckusick ufs_reclaim, /* reclaim */ 13939597Smckusick ufs_lock, /* lock */ 14039597Smckusick ufs_unlock, /* unlock */ 14139674Smckusick spec_bmap, /* bmap */ 14239597Smckusick spec_strategy, /* strategy */ 14339674Smckusick ufs_print, /* print */ 14439909Smckusick ufs_islocked, /* islocked */ 14539435Smckusick }; 14639435Smckusick 14740290Smckusick #ifdef FIFO 14840290Smckusick int fifo_lookup(), 14940290Smckusick fifo_open(), 15040290Smckusick ufsfifo_read(), 15140290Smckusick ufsfifo_write(), 15240290Smckusick fifo_bmap(), 15340290Smckusick fifo_ioctl(), 15440290Smckusick fifo_select(), 15540290Smckusick ufsfifo_close(), 15640290Smckusick fifo_print(), 15740290Smckusick fifo_badop(), 15840290Smckusick fifo_nullop(); 15940290Smckusick 16040290Smckusick struct vnodeops fifo_inodeops = { 16140290Smckusick fifo_lookup, /* lookup */ 16240290Smckusick fifo_badop, /* create */ 16340290Smckusick fifo_badop, /* mknod */ 16440290Smckusick fifo_open, /* open */ 16540290Smckusick ufsfifo_close, /* close */ 16640290Smckusick ufs_access, /* access */ 16740290Smckusick ufs_getattr, /* getattr */ 16840290Smckusick ufs_setattr, /* setattr */ 16940290Smckusick ufsfifo_read, /* read */ 17040290Smckusick ufsfifo_write, /* write */ 17140290Smckusick fifo_ioctl, /* ioctl */ 17240290Smckusick fifo_select, /* select */ 17340290Smckusick fifo_badop, /* mmap */ 17440290Smckusick fifo_nullop, /* fsync */ 17540290Smckusick fifo_badop, /* seek */ 17640290Smckusick fifo_badop, /* remove */ 17740290Smckusick fifo_badop, /* link */ 17840290Smckusick fifo_badop, /* rename */ 17940290Smckusick fifo_badop, /* mkdir */ 18040290Smckusick fifo_badop, /* rmdir */ 18140290Smckusick fifo_badop, /* symlink */ 18240290Smckusick fifo_badop, /* readdir */ 18340290Smckusick fifo_badop, /* readlink */ 18440290Smckusick fifo_badop, /* abortop */ 18540290Smckusick ufs_inactive, /* inactive */ 18640290Smckusick ufs_reclaim, /* reclaim */ 18740290Smckusick ufs_lock, /* lock */ 18840290Smckusick ufs_unlock, /* unlock */ 18940290Smckusick fifo_bmap, /* bmap */ 19040290Smckusick fifo_badop, /* strategy */ 19140290Smckusick ufs_print, /* print */ 19240290Smckusick ufs_islocked, /* islocked */ 19337737Smckusick }; 19440290Smckusick #endif /* FIFO */ 19540290Smckusick 19640290Smckusick enum vtype iftovt_tab[16] = { 19740290Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 19840290Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 19937737Smckusick }; 20040290Smckusick int vttoif_tab[9] = { 20140290Smckusick 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT, 20240290Smckusick }; 2036254Sroot 2049167Ssam /* 20537737Smckusick * Create a regular file 2069167Ssam */ 20737737Smckusick ufs_create(ndp, vap) 20837737Smckusick struct nameidata *ndp; 20937737Smckusick struct vattr *vap; 2106254Sroot { 21137737Smckusick struct inode *ip; 21237737Smckusick int error; 2136254Sroot 21437737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 21537737Smckusick return (error); 21637737Smckusick ndp->ni_vp = ITOV(ip); 21737737Smckusick return (0); 2186254Sroot } 2196254Sroot 22037Sbill /* 22137737Smckusick * Mknod vnode call 2226254Sroot */ 22337737Smckusick /* ARGSUSED */ 22437737Smckusick ufs_mknod(ndp, vap, cred) 22537737Smckusick struct nameidata *ndp; 22637737Smckusick struct ucred *cred; 22737737Smckusick struct vattr *vap; 2286254Sroot { 22939435Smckusick register struct vnode *vp; 23037737Smckusick struct inode *ip; 23137737Smckusick int error; 2326254Sroot 23337737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 23437737Smckusick return (error); 23540290Smckusick ip->i_flag |= IACC|IUPD|ICHG; 23640290Smckusick if (vap->va_rdev != VNOVAL) { 23737737Smckusick /* 23837737Smckusick * Want to be able to use this to make badblock 23937737Smckusick * inodes, so don't truncate the dev number. 24037737Smckusick */ 24139608Smckusick ip->i_rdev = vap->va_rdev; 24212756Ssam } 24337737Smckusick /* 24437737Smckusick * Remove inode so that it will be reloaded by iget and 24537737Smckusick * checked to see if it is an alias of an existing entry 24637737Smckusick * in the inode cache. 24737737Smckusick */ 24840290Smckusick vp = ITOV(ip); 24940290Smckusick vput(vp); 25039435Smckusick vp->v_type = VNON; 25139435Smckusick vgone(vp); 25237737Smckusick return (0); 2536254Sroot } 2546254Sroot 2556254Sroot /* 25637737Smckusick * Open called. 25737737Smckusick * 25837737Smckusick * Nothing to do. 2596254Sroot */ 26037737Smckusick /* ARGSUSED */ 26137737Smckusick ufs_open(vp, mode, cred) 26237737Smckusick struct vnode *vp; 26337737Smckusick int mode; 26437737Smckusick struct ucred *cred; 2656254Sroot { 2666254Sroot 26737737Smckusick return (0); 2686254Sroot } 2696254Sroot 2706254Sroot /* 27137737Smckusick * Close called 27237737Smckusick * 27337737Smckusick * Update the times on the inode. 2746254Sroot */ 27537737Smckusick /* ARGSUSED */ 27637737Smckusick ufs_close(vp, fflag, cred) 27737737Smckusick struct vnode *vp; 27837737Smckusick int fflag; 27937737Smckusick struct ucred *cred; 2806254Sroot { 28137737Smckusick register struct inode *ip = VTOI(vp); 2826254Sroot 28339815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 28437737Smckusick ITIMES(ip, &time, &time); 28537737Smckusick return (0); 2866254Sroot } 2876254Sroot 28841312Smckusick /* 28941312Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 29041312Smckusick * The mode is shifted to select the owner/group/other fields. The 29141312Smckusick * super user is granted all permissions. 29241312Smckusick */ 29337737Smckusick ufs_access(vp, mode, cred) 29437737Smckusick struct vnode *vp; 29541312Smckusick register int mode; 29637737Smckusick struct ucred *cred; 2976254Sroot { 29841312Smckusick register struct inode *ip = VTOI(vp); 29941312Smckusick register gid_t *gp; 30041312Smckusick int i, error; 3016254Sroot 30241312Smckusick #ifdef DIAGNOSTIC 30341312Smckusick if (!VOP_ISLOCKED(vp)) { 30441312Smckusick vprint("ufs_access: not locked", vp); 30541312Smckusick panic("ufs_access: not locked"); 30641312Smckusick } 30741312Smckusick #endif 30841312Smckusick #ifdef QUOTA 30941312Smckusick if (mode & VWRITE) { 31041312Smckusick switch (vp->v_type) { 31141312Smckusick case VREG: case VDIR: case VLNK: 31241312Smckusick if (error = getinoquota(ip)) 31341312Smckusick return (error); 31441312Smckusick } 31541312Smckusick } 31641312Smckusick #endif /* QUOTA */ 31741312Smckusick /* 31841312Smckusick * If you're the super-user, you always get access. 31941312Smckusick */ 32041312Smckusick if (cred->cr_uid == 0) 32141312Smckusick return (0); 32241312Smckusick /* 32341312Smckusick * Access check is based on only one of owner, group, public. 32441312Smckusick * If not owner, then check group. If not a member of the 32541312Smckusick * group, then check public access. 32641312Smckusick */ 32741312Smckusick if (cred->cr_uid != ip->i_uid) { 32841312Smckusick mode >>= 3; 32941312Smckusick gp = cred->cr_groups; 33041312Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 33141312Smckusick if (ip->i_gid == *gp) 33241312Smckusick goto found; 33341312Smckusick mode >>= 3; 33441312Smckusick found: 33541312Smckusick ; 33641312Smckusick } 33741312Smckusick if ((ip->i_mode & mode) != 0) 33841312Smckusick return (0); 33941312Smckusick return (EACCES); 3406254Sroot } 3416254Sroot 34237737Smckusick /* ARGSUSED */ 34337737Smckusick ufs_getattr(vp, vap, cred) 34437737Smckusick struct vnode *vp; 34537737Smckusick register struct vattr *vap; 34637737Smckusick struct ucred *cred; 3476254Sroot { 34837737Smckusick register struct inode *ip = VTOI(vp); 3496254Sroot 35037737Smckusick ITIMES(ip, &time, &time); 3516254Sroot /* 35237737Smckusick * Copy from inode table 3536254Sroot */ 35437737Smckusick vap->va_fsid = ip->i_dev; 35537737Smckusick vap->va_fileid = ip->i_number; 35637737Smckusick vap->va_mode = ip->i_mode & ~IFMT; 35737737Smckusick vap->va_nlink = ip->i_nlink; 35837737Smckusick vap->va_uid = ip->i_uid; 35937737Smckusick vap->va_gid = ip->i_gid; 36037737Smckusick vap->va_rdev = (dev_t)ip->i_rdev; 36141312Smckusick #ifdef tahoe 36241312Smckusick vap->va_size = ip->i_size; 36341312Smckusick vap->va_size_rsv = 0; 36441312Smckusick #else 36540641Smckusick vap->va_qsize = ip->i_din.di_qsize; 36641312Smckusick #endif 36737737Smckusick vap->va_atime.tv_sec = ip->i_atime; 36838578Smckusick vap->va_atime.tv_usec = 0; 36937737Smckusick vap->va_mtime.tv_sec = ip->i_mtime; 37038578Smckusick vap->va_mtime.tv_usec = 0; 37137737Smckusick vap->va_ctime.tv_sec = ip->i_ctime; 37238578Smckusick vap->va_ctime.tv_usec = 0; 37338254Smckusick vap->va_flags = ip->i_flags; 37438254Smckusick vap->va_gen = ip->i_gen; 37537737Smckusick /* this doesn't belong here */ 37637737Smckusick if (vp->v_type == VBLK) 37737737Smckusick vap->va_blocksize = BLKDEV_IOSIZE; 37837737Smckusick else if (vp->v_type == VCHR) 37937737Smckusick vap->va_blocksize = MAXBSIZE; 3807142Smckusick else 38137737Smckusick vap->va_blocksize = ip->i_fs->fs_bsize; 38238657Smckusick vap->va_bytes = dbtob(ip->i_blocks); 38340641Smckusick vap->va_bytes_rsv = 0; 38437737Smckusick vap->va_type = vp->v_type; 38537737Smckusick return (0); 3866254Sroot } 3876254Sroot 3886254Sroot /* 38937737Smckusick * Set attribute vnode op. called from several syscalls 3906254Sroot */ 39137737Smckusick ufs_setattr(vp, vap, cred) 39237737Smckusick register struct vnode *vp; 39337737Smckusick register struct vattr *vap; 39437737Smckusick register struct ucred *cred; 3956254Sroot { 39637737Smckusick register struct inode *ip = VTOI(vp); 39737737Smckusick int error = 0; 3986254Sroot 39937737Smckusick /* 40037737Smckusick * Check for unsetable attributes. 40137737Smckusick */ 40237737Smckusick if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 40337737Smckusick (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 40437737Smckusick (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 40538254Smckusick ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 40637737Smckusick return (EINVAL); 40716540Ssam } 40837737Smckusick /* 40937737Smckusick * Go through the fields and update iff not VNOVAL. 41037737Smckusick */ 41137737Smckusick if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) 41237737Smckusick if (error = chown1(vp, vap->va_uid, vap->va_gid, cred)) 41337737Smckusick return (error); 41437737Smckusick if (vap->va_size != VNOVAL) { 41537737Smckusick if (vp->v_type == VDIR) 41637737Smckusick return (EISDIR); 41739674Smckusick if (error = itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */ 41837737Smckusick return (error); 41913878Ssam } 42037737Smckusick if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 42137773Smckusick if (cred->cr_uid != ip->i_uid && 42237773Smckusick (error = suser(cred, &u.u_acflag))) 42337773Smckusick return (error); 42437737Smckusick if (vap->va_atime.tv_sec != VNOVAL) 42537737Smckusick ip->i_flag |= IACC; 42637737Smckusick if (vap->va_mtime.tv_sec != VNOVAL) 42737737Smckusick ip->i_flag |= IUPD; 42837737Smckusick ip->i_flag |= ICHG; 42937737Smckusick if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) 43037737Smckusick return (error); 4316254Sroot } 43237737Smckusick if (vap->va_mode != (u_short)VNOVAL) 43337737Smckusick error = chmod1(vp, (int)vap->va_mode, cred); 43438254Smckusick if (vap->va_flags != VNOVAL) { 43538254Smckusick if (cred->cr_uid != ip->i_uid && 43638254Smckusick (error = suser(cred, &u.u_acflag))) 43738254Smckusick return (error); 43838254Smckusick if (cred->cr_uid == 0) { 43938254Smckusick ip->i_flags = vap->va_flags; 44038254Smckusick } else { 44138254Smckusick ip->i_flags &= 0xffff0000; 44238254Smckusick ip->i_flags |= (vap->va_flags & 0xffff); 44338254Smckusick } 44438254Smckusick ip->i_flag |= ICHG; 44538254Smckusick } 44637737Smckusick return (error); 4476254Sroot } 4486254Sroot 4496254Sroot /* 4509167Ssam * Change the mode on a file. 4519167Ssam * Inode must be locked before calling. 4529167Ssam */ 45337737Smckusick chmod1(vp, mode, cred) 45437737Smckusick register struct vnode *vp; 4557701Ssam register int mode; 45637737Smckusick struct ucred *cred; 4577701Ssam { 45837737Smckusick register struct inode *ip = VTOI(vp); 45937773Smckusick int error; 4607868Sroot 46137773Smckusick if (cred->cr_uid != ip->i_uid && 46237773Smckusick (error = suser(cred, &u.u_acflag))) 46337773Smckusick return (error); 4646254Sroot ip->i_mode &= ~07777; 46537737Smckusick if (cred->cr_uid) { 46637737Smckusick if (vp->v_type != VDIR) 46721015Smckusick mode &= ~ISVTX; 46837737Smckusick if (!groupmember(ip->i_gid, cred)) 46911811Ssam mode &= ~ISGID; 4707439Sroot } 47137737Smckusick ip->i_mode |= mode & 07777; 4726254Sroot ip->i_flag |= ICHG; 47337737Smckusick if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) 47437737Smckusick xrele(vp); 47521015Smckusick return (0); 4765992Swnj } 4775992Swnj 4789167Ssam /* 4797701Ssam * Perform chown operation on inode ip; 4807701Ssam * inode must be locked prior to call. 4817701Ssam */ 48237737Smckusick chown1(vp, uid, gid, cred) 48337737Smckusick register struct vnode *vp; 48437737Smckusick uid_t uid; 48537737Smckusick gid_t gid; 48637737Smckusick struct ucred *cred; 4877701Ssam { 48837737Smckusick register struct inode *ip = VTOI(vp); 48941312Smckusick uid_t ouid; 49041312Smckusick gid_t ogid; 49141312Smckusick int error = 0; 4927701Ssam #ifdef QUOTA 49341312Smckusick register int i; 49441312Smckusick long change; 49511811Ssam #endif 4967701Ssam 49737737Smckusick if (uid == (u_short)VNOVAL) 49811811Ssam uid = ip->i_uid; 49937737Smckusick if (gid == (u_short)VNOVAL) 50011811Ssam gid = ip->i_gid; 50136614Sbostic /* 50236614Sbostic * If we don't own the file, are trying to change the owner 50336614Sbostic * of the file, or are not a member of the target group, 50436614Sbostic * the caller must be superuser or the call fails. 50536614Sbostic */ 50637737Smckusick if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || 50737737Smckusick !groupmember((gid_t)gid, cred)) && 50837737Smckusick (error = suser(cred, &u.u_acflag))) 50937737Smckusick return (error); 51041312Smckusick ouid = ip->i_uid; 51141312Smckusick ogid = ip->i_gid; 51211811Ssam #ifdef QUOTA 51341312Smckusick if (error = getinoquota(ip)) 51441312Smckusick return (error); 51541312Smckusick if (ouid == uid) { 51641312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 51741312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 51841312Smckusick } 51941312Smckusick if (ogid == gid) { 52041312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 52141312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 52241312Smckusick } 52341312Smckusick change = ip->i_blocks; 52441312Smckusick (void) chkdq(ip, -change, cred, CHOWN); 52541312Smckusick (void) chkiq(ip, -1, cred, CHOWN); 52641312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 52741312Smckusick dqrele(vp, ip->i_dquot[i]); 52841312Smckusick ip->i_dquot[i] = NODQUOT; 52941312Smckusick } 5307482Skre #endif 53111811Ssam ip->i_uid = uid; 53211811Ssam ip->i_gid = gid; 5337701Ssam #ifdef QUOTA 53441312Smckusick if ((error = getinoquota(ip)) == 0) { 53541312Smckusick if (ouid == uid) { 53641312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 53741312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 53841312Smckusick } 53941312Smckusick if (ogid == gid) { 54041312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 54141312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 54241312Smckusick } 54341312Smckusick if ((error = chkdq(ip, change, cred, CHOWN)) == 0) { 54441312Smckusick if ((error = chkiq(ip, 1, cred, CHOWN)) == 0) 54541927Smckusick goto good; 54641312Smckusick else 54741312Smckusick (void) chkdq(ip, -change, cred, CHOWN|FORCE); 54841312Smckusick } 54941312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 55041312Smckusick dqrele(vp, ip->i_dquot[i]); 55141312Smckusick ip->i_dquot[i] = NODQUOT; 55241312Smckusick } 55341312Smckusick } 55441312Smckusick ip->i_uid = ouid; 55541312Smckusick ip->i_gid = ogid; 55641312Smckusick if (getinoquota(ip) == 0) { 55741312Smckusick if (ouid == uid) { 55841312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 55941312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 56041312Smckusick } 56141312Smckusick if (ogid == gid) { 56241312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 56341312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 56441312Smckusick } 56541927Smckusick (void) chkdq(ip, change, cred, FORCE|CHOWN); 56641927Smckusick (void) chkiq(ip, 1, cred, FORCE|CHOWN); 56742440Smckusick (void) getinoquota(ip); 56841312Smckusick } 56942440Smckusick return (error); 57041927Smckusick good: 57142440Smckusick if (getinoquota(ip)) 57242440Smckusick panic("chown: lost quota"); 57342440Smckusick #endif /* QUOTA */ 57441312Smckusick if (ouid != uid || ogid != gid) 57541312Smckusick ip->i_flag |= ICHG; 57641312Smckusick if (ouid != uid && cred->cr_uid != 0) 57741312Smckusick ip->i_mode &= ~ISUID; 57841312Smckusick if (ogid != gid && cred->cr_uid != 0) 57941312Smckusick ip->i_mode &= ~ISGID; 58012646Ssam return (0); 58137Sbill } 58237Sbill 58339608Smckusick /* 58439608Smckusick * Vnode op for reading. 58539608Smckusick */ 58637737Smckusick /* ARGSUSED */ 58739608Smckusick ufs_read(vp, uio, ioflag, cred) 58839608Smckusick struct vnode *vp; 58939608Smckusick register struct uio *uio; 59039608Smckusick int ioflag; 59139608Smckusick struct ucred *cred; 59239608Smckusick { 59339608Smckusick register struct inode *ip = VTOI(vp); 59439608Smckusick register struct fs *fs; 59539608Smckusick struct buf *bp; 59639608Smckusick daddr_t lbn, bn, rablock; 59739896Smckusick int size, diff, error = 0; 59839608Smckusick long n, on, type; 59939608Smckusick 60039608Smckusick if (uio->uio_rw != UIO_READ) 60139608Smckusick panic("ufs_read mode"); 60239608Smckusick type = ip->i_mode & IFMT; 60339608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 60439608Smckusick panic("ufs_read type"); 60539608Smckusick if (uio->uio_resid == 0) 60639608Smckusick return (0); 60739608Smckusick if (uio->uio_offset < 0) 60839608Smckusick return (EINVAL); 60939608Smckusick ip->i_flag |= IACC; 61039608Smckusick fs = ip->i_fs; 61139608Smckusick do { 61239608Smckusick lbn = lblkno(fs, uio->uio_offset); 61339608Smckusick on = blkoff(fs, uio->uio_offset); 61439608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 61539608Smckusick diff = ip->i_size - uio->uio_offset; 61639608Smckusick if (diff <= 0) 61739608Smckusick return (0); 61839608Smckusick if (diff < n) 61939608Smckusick n = diff; 62039608Smckusick size = blksize(fs, ip, lbn); 62139674Smckusick rablock = lbn + 1; 62239896Smckusick if (vp->v_lastr + 1 == lbn && 62339896Smckusick lblktosize(fs, rablock) < ip->i_size) 62439896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 62539896Smckusick blksize(fs, ip, rablock), NOCRED, &bp); 62639608Smckusick else 62739674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 62839815Smckusick vp->v_lastr = lbn; 62939608Smckusick n = MIN(n, size - bp->b_resid); 63039608Smckusick if (error) { 63139608Smckusick brelse(bp); 63239608Smckusick return (error); 63339608Smckusick } 63439608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 63539608Smckusick if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size) 63639608Smckusick bp->b_flags |= B_AGE; 63739608Smckusick brelse(bp); 63839608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 63939608Smckusick return (error); 64039608Smckusick } 64139608Smckusick 64239608Smckusick /* 64339608Smckusick * Vnode op for writing. 64439608Smckusick */ 64539608Smckusick ufs_write(vp, uio, ioflag, cred) 64639608Smckusick register struct vnode *vp; 64739608Smckusick struct uio *uio; 64839608Smckusick int ioflag; 64939608Smckusick struct ucred *cred; 65039608Smckusick { 65139608Smckusick register struct inode *ip = VTOI(vp); 65239608Smckusick register struct fs *fs; 65339608Smckusick struct buf *bp; 65439608Smckusick daddr_t lbn, bn; 65539608Smckusick u_long osize; 65639608Smckusick int i, n, on, flags; 65739608Smckusick int count, size, resid, error = 0; 65839608Smckusick 65939608Smckusick if (uio->uio_rw != UIO_WRITE) 66039608Smckusick panic("ufs_write mode"); 66139608Smckusick switch (vp->v_type) { 66239608Smckusick case VREG: 66339608Smckusick if (ioflag & IO_APPEND) 66439608Smckusick uio->uio_offset = ip->i_size; 66539608Smckusick /* fall through */ 66639608Smckusick case VLNK: 66739608Smckusick break; 66839608Smckusick 66939608Smckusick case VDIR: 67039608Smckusick if ((ioflag & IO_SYNC) == 0) 67139608Smckusick panic("ufs_write nonsync dir write"); 67239608Smckusick break; 67339608Smckusick 67439608Smckusick default: 67539608Smckusick panic("ufs_write type"); 67639608Smckusick } 67739608Smckusick if (uio->uio_offset < 0) 67839608Smckusick return (EINVAL); 67939608Smckusick if (uio->uio_resid == 0) 68039608Smckusick return (0); 68139608Smckusick /* 68239608Smckusick * Maybe this should be above the vnode op call, but so long as 68339608Smckusick * file servers have no limits, i don't think it matters 68439608Smckusick */ 68539608Smckusick if (vp->v_type == VREG && 68639608Smckusick uio->uio_offset + uio->uio_resid > 68739608Smckusick u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { 68839608Smckusick psignal(u.u_procp, SIGXFSZ); 68939608Smckusick return (EFBIG); 69039608Smckusick } 69139608Smckusick resid = uio->uio_resid; 69239608Smckusick osize = ip->i_size; 69339608Smckusick fs = ip->i_fs; 69439674Smckusick flags = 0; 69539674Smckusick if (ioflag & IO_SYNC) 69639674Smckusick flags = B_SYNC; 69739608Smckusick do { 69839608Smckusick lbn = lblkno(fs, uio->uio_offset); 69939608Smckusick on = blkoff(fs, uio->uio_offset); 70039608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 70139608Smckusick if (n < fs->fs_bsize) 70239674Smckusick flags |= B_CLRBUF; 70339608Smckusick else 70439674Smckusick flags &= ~B_CLRBUF; 70539674Smckusick if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) 70639608Smckusick break; 70739674Smckusick bn = bp->b_blkno; 70839608Smckusick if (uio->uio_offset + n > ip->i_size) 70939608Smckusick ip->i_size = uio->uio_offset + n; 71039608Smckusick size = blksize(fs, ip, lbn); 71139608Smckusick count = howmany(size, CLBYTES); 71239608Smckusick for (i = 0; i < count; i++) 71339608Smckusick munhash(ip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); 71439608Smckusick n = MIN(n, size - bp->b_resid); 71539608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 71639608Smckusick if (ioflag & IO_SYNC) 71739608Smckusick (void) bwrite(bp); 71839608Smckusick else if (n + on == fs->fs_bsize) { 71939608Smckusick bp->b_flags |= B_AGE; 72039608Smckusick bawrite(bp); 72139608Smckusick } else 72239608Smckusick bdwrite(bp); 72339608Smckusick ip->i_flag |= IUPD|ICHG; 72439608Smckusick if (cred->cr_uid != 0) 72539608Smckusick ip->i_mode &= ~(ISUID|ISGID); 72639608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 72739608Smckusick if (error && (ioflag & IO_UNIT)) { 72839674Smckusick (void) itrunc(ip, osize, ioflag & IO_SYNC); 72939608Smckusick uio->uio_offset -= resid - uio->uio_resid; 73039608Smckusick uio->uio_resid = resid; 73139608Smckusick } 73242493Smckusick if (!error && (ioflag & IO_SYNC)) 73342493Smckusick error = iupdat(ip, &time, &time, 1); 73439608Smckusick return (error); 73539608Smckusick } 73639608Smckusick 73739608Smckusick /* ARGSUSED */ 73837737Smckusick ufs_ioctl(vp, com, data, fflag, cred) 73937737Smckusick struct vnode *vp; 74037737Smckusick int com; 74137737Smckusick caddr_t data; 74237737Smckusick int fflag; 74337737Smckusick struct ucred *cred; 74411811Ssam { 74511811Ssam 74637737Smckusick return (ENOTTY); 74711811Ssam } 74811811Ssam 74937737Smckusick /* ARGSUSED */ 75040290Smckusick ufs_select(vp, which, fflags, cred) 75137737Smckusick struct vnode *vp; 75240290Smckusick int which, fflags; 75337737Smckusick struct ucred *cred; 75437737Smckusick { 75537737Smckusick 75637737Smckusick return (1); /* XXX */ 75737737Smckusick } 75837737Smckusick 7599167Ssam /* 76037737Smckusick * Mmap a file 76137737Smckusick * 76237737Smckusick * NB Currently unsupported. 7639167Ssam */ 76437737Smckusick /* ARGSUSED */ 76537737Smckusick ufs_mmap(vp, fflags, cred) 76637737Smckusick struct vnode *vp; 76737737Smckusick int fflags; 76837737Smckusick struct ucred *cred; 76937Sbill { 77037Sbill 77137737Smckusick return (EINVAL); 77237Sbill } 7737535Sroot 7749167Ssam /* 77537737Smckusick * Synch an open file. 7769167Ssam */ 77737737Smckusick /* ARGSUSED */ 77839597Smckusick ufs_fsync(vp, fflags, cred, waitfor) 77937737Smckusick struct vnode *vp; 78037737Smckusick int fflags; 78137737Smckusick struct ucred *cred; 78239597Smckusick int waitfor; 7837701Ssam { 78439597Smckusick struct inode *ip = VTOI(vp); 7857701Ssam 78637737Smckusick if (fflags&FWRITE) 78737737Smckusick ip->i_flag |= ICHG; 78839674Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 78939674Smckusick return (iupdat(ip, &time, &time, waitfor == MNT_WAIT)); 7907701Ssam } 7917701Ssam 7929167Ssam /* 79337737Smckusick * Seek on a file 79437737Smckusick * 79537737Smckusick * Nothing to do, so just return. 7969167Ssam */ 79737737Smckusick /* ARGSUSED */ 79837737Smckusick ufs_seek(vp, oldoff, newoff, cred) 79937737Smckusick struct vnode *vp; 80037737Smckusick off_t oldoff, newoff; 80137737Smckusick struct ucred *cred; 8027701Ssam { 8037701Ssam 80437737Smckusick return (0); 80537737Smckusick } 80637737Smckusick 80737737Smckusick /* 80837737Smckusick * ufs remove 80937737Smckusick * Hard to avoid races here, especially 81037737Smckusick * in unlinking directories. 81137737Smckusick */ 81237737Smckusick ufs_remove(ndp) 81337737Smckusick struct nameidata *ndp; 81437737Smckusick { 81537737Smckusick register struct inode *ip, *dp; 81637737Smckusick int error; 81737737Smckusick 81837737Smckusick ip = VTOI(ndp->ni_vp); 81937737Smckusick dp = VTOI(ndp->ni_dvp); 82037737Smckusick error = dirremove(ndp); 82137737Smckusick if (!error) { 82237737Smckusick ip->i_nlink--; 82337737Smckusick ip->i_flag |= ICHG; 8247701Ssam } 82537737Smckusick if (dp == ip) 82637737Smckusick vrele(ITOV(ip)); 82737737Smckusick else 82837737Smckusick iput(ip); 82937737Smckusick iput(dp); 83037737Smckusick return (error); 8317701Ssam } 8327701Ssam 8339167Ssam /* 83437737Smckusick * link vnode call 8359167Ssam */ 83637737Smckusick ufs_link(vp, ndp) 83737737Smckusick register struct vnode *vp; 83837737Smckusick register struct nameidata *ndp; 8399167Ssam { 84037737Smckusick register struct inode *ip = VTOI(vp); 84137737Smckusick int error; 8429167Ssam 84337737Smckusick if (ndp->ni_dvp != vp) 84437737Smckusick ILOCK(ip); 84537737Smckusick if (ip->i_nlink == LINK_MAX - 1) { 84637737Smckusick error = EMLINK; 84737737Smckusick goto out; 84837737Smckusick } 84937737Smckusick ip->i_nlink++; 85037737Smckusick ip->i_flag |= ICHG; 85137737Smckusick error = iupdat(ip, &time, &time, 1); 85237737Smckusick if (!error) 85337737Smckusick error = direnter(ip, ndp); 85437737Smckusick out: 85537737Smckusick if (ndp->ni_dvp != vp) 85637737Smckusick IUNLOCK(ip); 85737737Smckusick if (error) { 85837737Smckusick ip->i_nlink--; 85930598Smckusick ip->i_flag |= ICHG; 86037737Smckusick } 86137737Smckusick return (error); 8629167Ssam } 8639167Ssam 8649167Ssam /* 8659167Ssam * Rename system call. 8669167Ssam * rename("foo", "bar"); 8679167Ssam * is essentially 8689167Ssam * unlink("bar"); 8699167Ssam * link("foo", "bar"); 8709167Ssam * unlink("foo"); 8719167Ssam * but ``atomically''. Can't do full commit without saving state in the 8729167Ssam * inode on disk which isn't feasible at this time. Best we can do is 8739167Ssam * always guarantee the target exists. 8749167Ssam * 8759167Ssam * Basic algorithm is: 8769167Ssam * 8779167Ssam * 1) Bump link count on source while we're linking it to the 87837737Smckusick * target. This also ensure the inode won't be deleted out 87916776Smckusick * from underneath us while we work (it may be truncated by 88016776Smckusick * a concurrent `trunc' or `open' for creation). 8819167Ssam * 2) Link source to destination. If destination already exists, 8829167Ssam * delete it first. 88316776Smckusick * 3) Unlink source reference to inode if still around. If a 88416776Smckusick * directory was moved and the parent of the destination 8859167Ssam * is different from the source, patch the ".." entry in the 8869167Ssam * directory. 8879167Ssam */ 88837737Smckusick ufs_rename(fndp, tndp) 88937737Smckusick register struct nameidata *fndp, *tndp; 8907701Ssam { 8919167Ssam register struct inode *ip, *xp, *dp; 89216776Smckusick struct dirtemplate dirbuf; 89316776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 89410051Ssam int error = 0; 8957701Ssam 89637737Smckusick dp = VTOI(fndp->ni_dvp); 89737737Smckusick ip = VTOI(fndp->ni_vp); 89837737Smckusick ILOCK(ip); 8999167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 90037737Smckusick register struct direct *d = &fndp->ni_dent; 9019167Ssam 9029167Ssam /* 90311641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 9049167Ssam */ 90537737Smckusick if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip || 90637737Smckusick fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { 90742466Smckusick VOP_ABORTOP(tndp); 90842466Smckusick vput(tndp->ni_dvp); 90942466Smckusick if (tndp->ni_vp) 91042466Smckusick vput(tndp->ni_vp); 91142466Smckusick VOP_ABORTOP(fndp); 91242466Smckusick vrele(fndp->ni_dvp); 91342466Smckusick vput(fndp->ni_vp); 91437737Smckusick return (EINVAL); 9159167Ssam } 91616776Smckusick ip->i_flag |= IRENAME; 9179167Ssam oldparent = dp->i_number; 9189167Ssam doingdirectory++; 9199167Ssam } 92037737Smckusick vrele(fndp->ni_dvp); 9219167Ssam 9229167Ssam /* 9239167Ssam * 1) Bump link count while we're moving stuff 9249167Ssam * around. If we crash somewhere before 9259167Ssam * completing our work, the link count 9269167Ssam * may be wrong, but correctable. 9279167Ssam */ 9289167Ssam ip->i_nlink++; 9299167Ssam ip->i_flag |= ICHG; 93037737Smckusick error = iupdat(ip, &time, &time, 1); 93116664Smckusick IUNLOCK(ip); 9329167Ssam 9339167Ssam /* 9349167Ssam * When the target exists, both the directory 93537737Smckusick * and target vnodes are returned locked. 9369167Ssam */ 93737737Smckusick dp = VTOI(tndp->ni_dvp); 93837737Smckusick xp = NULL; 93937737Smckusick if (tndp->ni_vp) 94037737Smckusick xp = VTOI(tndp->ni_vp); 9419167Ssam /* 94211641Ssam * If ".." must be changed (ie the directory gets a new 94312816Smckusick * parent) then the source directory must not be in the 94412816Smckusick * directory heirarchy above the target, as this would 94512816Smckusick * orphan everything below the source directory. Also 94612816Smckusick * the user must have write permission in the source so 94712816Smckusick * as to be able to change "..". We must repeat the call 94812816Smckusick * to namei, as the parent directory is unlocked by the 94912816Smckusick * call to checkpath(). 95011641Ssam */ 95116776Smckusick if (oldparent != dp->i_number) 95216776Smckusick newparent = dp->i_number; 95316776Smckusick if (doingdirectory && newparent) { 95441466Smckusick VOP_LOCK(fndp->ni_vp); 95541466Smckusick error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred); 95641466Smckusick VOP_UNLOCK(fndp->ni_vp); 95741466Smckusick if (error) 95812816Smckusick goto bad; 95937737Smckusick tndp->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 96012816Smckusick do { 96137737Smckusick dp = VTOI(tndp->ni_dvp); 96212816Smckusick if (xp != NULL) 96338069Smckusick iput(xp); 96437737Smckusick if (error = checkpath(ip, dp, tndp->ni_cred)) 96512816Smckusick goto out; 96637737Smckusick if (error = namei(tndp)) 96712816Smckusick goto out; 96837737Smckusick xp = NULL; 96937737Smckusick if (tndp->ni_vp) 97037737Smckusick xp = VTOI(tndp->ni_vp); 97137737Smckusick } while (dp != VTOI(tndp->ni_dvp)); 97212816Smckusick } 97311641Ssam /* 9749167Ssam * 2) If target doesn't exist, link the target 9759167Ssam * to the source and unlink the source. 9769167Ssam * Otherwise, rewrite the target directory 9779167Ssam * entry to reference the source inode and 9789167Ssam * expunge the original entry's existence. 9799167Ssam */ 9809167Ssam if (xp == NULL) { 98137737Smckusick if (dp->i_dev != ip->i_dev) 98237737Smckusick panic("rename: EXDEV"); 9839167Ssam /* 98416776Smckusick * Account for ".." in new directory. 98516776Smckusick * When source and destination have the same 98616776Smckusick * parent we don't fool with the link count. 9879167Ssam */ 98816776Smckusick if (doingdirectory && newparent) { 9899167Ssam dp->i_nlink++; 9909167Ssam dp->i_flag |= ICHG; 99137737Smckusick error = iupdat(dp, &time, &time, 1); 9929167Ssam } 99337737Smckusick if (error = direnter(ip, tndp)) 9949167Ssam goto out; 9959167Ssam } else { 99637737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 99737737Smckusick panic("rename: EXDEV"); 9989167Ssam /* 99910590Ssam * Short circuit rename(foo, foo). 100010590Ssam */ 100110590Ssam if (xp->i_number == ip->i_number) 100237737Smckusick panic("rename: same file"); 100310590Ssam /* 100424433Sbloom * If the parent directory is "sticky", then the user must 100524433Sbloom * own the parent directory, or the destination of the rename, 100624433Sbloom * otherwise the destination may not be changed (except by 100724433Sbloom * root). This implements append-only directories. 100824433Sbloom */ 100937737Smckusick if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && 101037737Smckusick tndp->ni_cred->cr_uid != dp->i_uid && 101137737Smckusick xp->i_uid != tndp->ni_cred->cr_uid) { 101224433Sbloom error = EPERM; 101324433Sbloom goto bad; 101424433Sbloom } 101524433Sbloom /* 101610051Ssam * Target must be empty if a directory 101710051Ssam * and have no links to it. 10189167Ssam * Also, insure source and target are 10199167Ssam * compatible (both directories, or both 10209167Ssam * not directories). 10219167Ssam */ 10229167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 102337737Smckusick if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 102437737Smckusick xp->i_nlink > 2) { 102510051Ssam error = ENOTEMPTY; 10269167Ssam goto bad; 10279167Ssam } 10289167Ssam if (!doingdirectory) { 102910051Ssam error = ENOTDIR; 10309167Ssam goto bad; 10319167Ssam } 103237737Smckusick cache_purge(ITOV(dp)); 10339167Ssam } else if (doingdirectory) { 103410051Ssam error = EISDIR; 10359167Ssam goto bad; 10369167Ssam } 103737737Smckusick if (error = dirrewrite(dp, ip, tndp)) 103837737Smckusick goto bad; 103937737Smckusick vput(ITOV(dp)); 10409167Ssam /* 104110051Ssam * Adjust the link count of the target to 104210051Ssam * reflect the dirrewrite above. If this is 104310051Ssam * a directory it is empty and there are 104410051Ssam * no links to it, so we can squash the inode and 104510051Ssam * any space associated with it. We disallowed 104610051Ssam * renaming over top of a directory with links to 104716776Smckusick * it above, as the remaining link would point to 104816776Smckusick * a directory without "." or ".." entries. 10499167Ssam */ 105010051Ssam xp->i_nlink--; 10519167Ssam if (doingdirectory) { 105210051Ssam if (--xp->i_nlink != 0) 105310051Ssam panic("rename: linked directory"); 105439674Smckusick error = itrunc(xp, (u_long)0, IO_SYNC); 105510051Ssam } 10569167Ssam xp->i_flag |= ICHG; 105738398Smckusick iput(xp); 105810246Ssam xp = NULL; 10599167Ssam } 10609167Ssam 10619167Ssam /* 10629167Ssam * 3) Unlink the source. 10639167Ssam */ 106437737Smckusick fndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 106537737Smckusick (void)namei(fndp); 106637737Smckusick if (fndp->ni_vp != NULL) { 106737737Smckusick xp = VTOI(fndp->ni_vp); 106837737Smckusick dp = VTOI(fndp->ni_dvp); 106937737Smckusick } else { 107038069Smckusick if (fndp->ni_dvp != NULL) 107138069Smckusick vput(fndp->ni_dvp); 107237737Smckusick xp = NULL; 107317758Smckusick dp = NULL; 107437737Smckusick } 10759167Ssam /* 107637737Smckusick * Ensure that the directory entry still exists and has not 107716776Smckusick * changed while the new name has been entered. If the source is 107816776Smckusick * a file then the entry may have been unlinked or renamed. In 107916776Smckusick * either case there is no further work to be done. If the source 108016776Smckusick * is a directory then it cannot have been rmdir'ed; its link 108116776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 108237737Smckusick * The IRENAME flag ensures that it cannot be moved by another 108316776Smckusick * rename. 10849167Ssam */ 108517758Smckusick if (xp != ip) { 108616776Smckusick if (doingdirectory) 108717758Smckusick panic("rename: lost dir entry"); 108816776Smckusick } else { 10899167Ssam /* 109016776Smckusick * If the source is a directory with a 109116776Smckusick * new parent, the link count of the old 109216776Smckusick * parent directory must be decremented 109316776Smckusick * and ".." set to point to the new parent. 10949167Ssam */ 109516776Smckusick if (doingdirectory && newparent) { 10969167Ssam dp->i_nlink--; 10979167Ssam dp->i_flag |= ICHG; 109839597Smckusick error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, 109937737Smckusick sizeof (struct dirtemplate), (off_t)0, 110039597Smckusick UIO_SYSSPACE, IO_NODELOCKED, 110139597Smckusick tndp->ni_cred, (int *)0); 110216776Smckusick if (error == 0) { 110316776Smckusick if (dirbuf.dotdot_namlen != 2 || 110416776Smckusick dirbuf.dotdot_name[0] != '.' || 110516776Smckusick dirbuf.dotdot_name[1] != '.') { 110639610Smckusick dirbad(xp, 12, "rename: mangled dir"); 110716776Smckusick } else { 110816776Smckusick dirbuf.dotdot_ino = newparent; 110939597Smckusick (void) vn_rdwr(UIO_WRITE, ITOV(xp), 111016776Smckusick (caddr_t)&dirbuf, 111116776Smckusick sizeof (struct dirtemplate), 111237740Smckusick (off_t)0, UIO_SYSSPACE, 111339597Smckusick IO_NODELOCKED|IO_SYNC, 111437737Smckusick tndp->ni_cred, (int *)0); 111537737Smckusick cache_purge(ITOV(dp)); 111616776Smckusick } 111716776Smckusick } 11189167Ssam } 111937737Smckusick error = dirremove(fndp); 112037737Smckusick if (!error) { 112116776Smckusick xp->i_nlink--; 112216776Smckusick xp->i_flag |= ICHG; 11239167Ssam } 112416776Smckusick xp->i_flag &= ~IRENAME; 11259167Ssam } 11269167Ssam if (dp) 112737737Smckusick vput(ITOV(dp)); 112816776Smckusick if (xp) 112937737Smckusick vput(ITOV(xp)); 113037737Smckusick vrele(ITOV(ip)); 113137737Smckusick return (error); 11329167Ssam 11339167Ssam bad: 11349167Ssam if (xp) 113537737Smckusick vput(ITOV(xp)); 113637737Smckusick vput(ITOV(dp)); 11379167Ssam out: 11389167Ssam ip->i_nlink--; 11399167Ssam ip->i_flag |= ICHG; 114037737Smckusick vrele(ITOV(ip)); 114137737Smckusick return (error); 11427701Ssam } 11437701Ssam 11447535Sroot /* 114512756Ssam * A virgin directory (no blushing please). 114612756Ssam */ 114712756Ssam struct dirtemplate mastertemplate = { 114812756Ssam 0, 12, 1, ".", 114912756Ssam 0, DIRBLKSIZ - 12, 2, ".." 115012756Ssam }; 115112756Ssam 115212756Ssam /* 115312756Ssam * Mkdir system call 115412756Ssam */ 115537737Smckusick ufs_mkdir(ndp, vap) 115637737Smckusick struct nameidata *ndp; 115737737Smckusick struct vattr *vap; 115812756Ssam { 115912756Ssam register struct inode *ip, *dp; 116037737Smckusick struct inode *tip; 116137737Smckusick struct vnode *dvp; 116212756Ssam struct dirtemplate dirtemplate; 116337737Smckusick int error; 116437737Smckusick int dmode; 116512756Ssam 116637737Smckusick dvp = ndp->ni_dvp; 116737737Smckusick dp = VTOI(dvp); 116837737Smckusick dmode = vap->va_mode&0777; 116937737Smckusick dmode |= IFDIR; 117012756Ssam /* 117112756Ssam * Must simulate part of maknode here 117212756Ssam * in order to acquire the inode, but 117312756Ssam * not have it entered in the parent 117412756Ssam * directory. The entry is made later 117512756Ssam * after writing "." and ".." entries out. 117612756Ssam */ 117741312Smckusick if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { 117812756Ssam iput(dp); 117937737Smckusick return (error); 118012756Ssam } 118137737Smckusick ip = tip; 118241312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 118341312Smckusick ip->i_gid = dp->i_gid; 118412756Ssam #ifdef QUOTA 118541312Smckusick if ((error = getinoquota(ip)) || 118641312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 118741312Smckusick ifree(ip, ip->i_number, dmode); 118841312Smckusick iput(ip); 118941312Smckusick iput(dp); 119041312Smckusick return (error); 119141312Smckusick } 119212756Ssam #endif 119312756Ssam ip->i_flag |= IACC|IUPD|ICHG; 119437737Smckusick ip->i_mode = dmode; 119537737Smckusick ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ 119612756Ssam ip->i_nlink = 2; 119737737Smckusick error = iupdat(ip, &time, &time, 1); 119812756Ssam 119912756Ssam /* 120012756Ssam * Bump link count in parent directory 120112756Ssam * to reflect work done below. Should 120212756Ssam * be done before reference is created 120312756Ssam * so reparation is possible if we crash. 120412756Ssam */ 120512756Ssam dp->i_nlink++; 120612756Ssam dp->i_flag |= ICHG; 120737737Smckusick error = iupdat(dp, &time, &time, 1); 120812756Ssam 120912756Ssam /* 121012756Ssam * Initialize directory with "." 121112756Ssam * and ".." from static template. 121212756Ssam */ 121312756Ssam dirtemplate = mastertemplate; 121412756Ssam dirtemplate.dot_ino = ip->i_number; 121512756Ssam dirtemplate.dotdot_ino = dp->i_number; 121639597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, 121737737Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 121839597Smckusick IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0); 121937737Smckusick if (error) { 122012756Ssam dp->i_nlink--; 122112756Ssam dp->i_flag |= ICHG; 122212756Ssam goto bad; 122312756Ssam } 122443288Smckusick if (DIRBLKSIZ > dp->i_fs->fs_fsize) { 122537737Smckusick panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ 122643288Smckusick } else { 122718103Smckusick ip->i_size = DIRBLKSIZ; 122843288Smckusick ip->i_flag |= ICHG; 122943288Smckusick } 123012756Ssam /* 123112756Ssam * Directory all set up, now 123212756Ssam * install the entry for it in 123312756Ssam * the parent directory. 123412756Ssam */ 123537737Smckusick error = direnter(ip, ndp); 123612756Ssam dp = NULL; 123737737Smckusick if (error) { 123816694Smckusick ndp->ni_nameiop = LOOKUP | NOCACHE; 123937737Smckusick error = namei(ndp); 124037737Smckusick if (!error) { 124137737Smckusick dp = VTOI(ndp->ni_vp); 124212756Ssam dp->i_nlink--; 124312756Ssam dp->i_flag |= ICHG; 124412756Ssam } 124512756Ssam } 124612756Ssam bad: 124712756Ssam /* 124812756Ssam * No need to do an explicit itrunc here, 124937737Smckusick * vrele will do this for us because we set 125012756Ssam * the link count to 0. 125112756Ssam */ 125237737Smckusick if (error) { 125312756Ssam ip->i_nlink = 0; 125412756Ssam ip->i_flag |= ICHG; 125538144Smckusick iput(ip); 125638144Smckusick } else 125738144Smckusick ndp->ni_vp = ITOV(ip); 125812756Ssam if (dp) 125912756Ssam iput(dp); 126037737Smckusick return (error); 126112756Ssam } 126212756Ssam 126312756Ssam /* 126412756Ssam * Rmdir system call. 126512756Ssam */ 126637737Smckusick ufs_rmdir(ndp) 126737737Smckusick register struct nameidata *ndp; 126812756Ssam { 126912756Ssam register struct inode *ip, *dp; 127037737Smckusick int error = 0; 127112756Ssam 127237737Smckusick ip = VTOI(ndp->ni_vp); 127337737Smckusick dp = VTOI(ndp->ni_dvp); 127412756Ssam /* 127512756Ssam * No rmdir "." please. 127612756Ssam */ 127712756Ssam if (dp == ip) { 127837737Smckusick vrele(ITOV(dp)); 127912756Ssam iput(ip); 128037737Smckusick return (EINVAL); 128112756Ssam } 128212756Ssam /* 128312756Ssam * Verify the directory is empty (and valid). 128412756Ssam * (Rmdir ".." won't be valid since 128512756Ssam * ".." will contain a reference to 128612756Ssam * the current directory and thus be 128712756Ssam * non-empty.) 128812756Ssam */ 128937737Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { 129037737Smckusick error = ENOTEMPTY; 129112756Ssam goto out; 129212756Ssam } 129312756Ssam /* 129412756Ssam * Delete reference to directory before purging 129512756Ssam * inode. If we crash in between, the directory 129612756Ssam * will be reattached to lost+found, 129712756Ssam */ 129837737Smckusick if (error = dirremove(ndp)) 129912756Ssam goto out; 130012756Ssam dp->i_nlink--; 130112756Ssam dp->i_flag |= ICHG; 130237737Smckusick cache_purge(ITOV(dp)); 130312756Ssam iput(dp); 130437737Smckusick ndp->ni_dvp = NULL; 130512756Ssam /* 130612756Ssam * Truncate inode. The only stuff left 130712756Ssam * in the directory is "." and "..". The 130812756Ssam * "." reference is inconsequential since 130912756Ssam * we're quashing it. The ".." reference 131012756Ssam * has already been adjusted above. We've 131112756Ssam * removed the "." reference and the reference 131212756Ssam * in the parent directory, but there may be 131312756Ssam * other hard links so decrement by 2 and 131412756Ssam * worry about them later. 131512756Ssam */ 131612756Ssam ip->i_nlink -= 2; 131739674Smckusick error = itrunc(ip, (u_long)0, IO_SYNC); 131837737Smckusick cache_purge(ITOV(ip)); 131912756Ssam out: 132037737Smckusick if (ndp->ni_dvp) 132112756Ssam iput(dp); 132212756Ssam iput(ip); 132337737Smckusick return (error); 132412756Ssam } 132512756Ssam 132637737Smckusick /* 132737737Smckusick * symlink -- make a symbolic link 132837737Smckusick */ 132937737Smckusick ufs_symlink(ndp, vap, target) 133037737Smckusick struct nameidata *ndp; 133137737Smckusick struct vattr *vap; 133237737Smckusick char *target; 133312756Ssam { 133437737Smckusick struct inode *ip; 133537737Smckusick int error; 133612756Ssam 133737737Smckusick error = maknode(IFLNK | vap->va_mode, ndp, &ip); 133837737Smckusick if (error) 133937737Smckusick return (error); 134039597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, 134139597Smckusick UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0); 134237737Smckusick iput(ip); 134337737Smckusick return (error); 134437737Smckusick } 134537737Smckusick 134637737Smckusick /* 134737737Smckusick * Vnode op for read and write 134837737Smckusick */ 134940345Smckusick ufs_readdir(vp, uio, cred, eofflagp) 135037737Smckusick struct vnode *vp; 135137737Smckusick register struct uio *uio; 135237737Smckusick struct ucred *cred; 135340345Smckusick int *eofflagp; 135437737Smckusick { 135539597Smckusick int count, lost, error; 135637737Smckusick 135737737Smckusick count = uio->uio_resid; 135837737Smckusick count &= ~(DIRBLKSIZ - 1); 135939597Smckusick lost = uio->uio_resid - count; 136039597Smckusick if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) 136137737Smckusick return (EINVAL); 136237737Smckusick uio->uio_resid = count; 136337737Smckusick uio->uio_iov->iov_len = count; 136439597Smckusick error = ufs_read(vp, uio, 0, cred); 136539597Smckusick uio->uio_resid += lost; 136640345Smckusick if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) 136740345Smckusick *eofflagp = 1; 136840345Smckusick else 136940345Smckusick *eofflagp = 0; 137037737Smckusick return (error); 137137737Smckusick } 137237737Smckusick 137337737Smckusick /* 137437737Smckusick * Return target name of a symbolic link 137537737Smckusick */ 137637737Smckusick ufs_readlink(vp, uiop, cred) 137737737Smckusick struct vnode *vp; 137837737Smckusick struct uio *uiop; 137937737Smckusick struct ucred *cred; 138037737Smckusick { 138137737Smckusick 138239597Smckusick return (ufs_read(vp, uiop, 0, cred)); 138337737Smckusick } 138437737Smckusick 138537737Smckusick /* 138637737Smckusick * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 138742466Smckusick * done. Nothing to do at the moment. 138837737Smckusick */ 138942466Smckusick /* ARGSUSED */ 139037737Smckusick ufs_abortop(ndp) 139142466Smckusick struct nameidata *ndp; 139237737Smckusick { 139337737Smckusick 139442466Smckusick return (0); 139512756Ssam } 139612756Ssam 139739909Smckusick /* 139839909Smckusick * Lock an inode. 139939909Smckusick */ 140037737Smckusick ufs_lock(vp) 140137737Smckusick struct vnode *vp; 140237737Smckusick { 140337737Smckusick register struct inode *ip = VTOI(vp); 140437737Smckusick 140537737Smckusick ILOCK(ip); 140637737Smckusick return (0); 140737737Smckusick } 140837737Smckusick 140939909Smckusick /* 141039909Smckusick * Unlock an inode. 141139909Smckusick */ 141237737Smckusick ufs_unlock(vp) 141337737Smckusick struct vnode *vp; 141437737Smckusick { 141537737Smckusick register struct inode *ip = VTOI(vp); 141637737Smckusick 141737737Smckusick if (!(ip->i_flag & ILOCKED)) 141837737Smckusick panic("ufs_unlock NOT LOCKED"); 141937737Smckusick IUNLOCK(ip); 142037737Smckusick return (0); 142137737Smckusick } 142237737Smckusick 142312756Ssam /* 142439909Smckusick * Check for a locked inode. 142539909Smckusick */ 142639909Smckusick ufs_islocked(vp) 142739909Smckusick struct vnode *vp; 142839909Smckusick { 142939909Smckusick 143039909Smckusick if (VTOI(vp)->i_flag & ILOCKED) 143139909Smckusick return (1); 143239909Smckusick return (0); 143339909Smckusick } 143439909Smckusick 143539909Smckusick /* 143637737Smckusick * Get access to bmap 143712756Ssam */ 143837737Smckusick ufs_bmap(vp, bn, vpp, bnp) 143937737Smckusick struct vnode *vp; 144037737Smckusick daddr_t bn; 144137737Smckusick struct vnode **vpp; 144237737Smckusick daddr_t *bnp; 144312756Ssam { 144437737Smckusick struct inode *ip = VTOI(vp); 144512756Ssam 144637737Smckusick if (vpp != NULL) 144737737Smckusick *vpp = ip->i_devvp; 144837737Smckusick if (bnp == NULL) 144937737Smckusick return (0); 145041538Smckusick return (bmap(ip, bn, bnp)); 145112756Ssam } 145237737Smckusick 145337737Smckusick /* 145441538Smckusick * Calculate the logical to physical mapping if not done already, 145541538Smckusick * then call the device strategy routine. 145637737Smckusick */ 145741538Smckusick int checkoverlap = 0; 145839674Smckusick 145937737Smckusick ufs_strategy(bp) 146037737Smckusick register struct buf *bp; 146137737Smckusick { 146239674Smckusick register struct inode *ip = VTOI(bp->b_vp); 146339674Smckusick struct vnode *vp; 146439674Smckusick int error; 146539674Smckusick 146639674Smckusick if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 146739674Smckusick panic("ufs_strategy: spec"); 146839674Smckusick if (bp->b_blkno == bp->b_lblkno) { 146939674Smckusick if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno)) 147039674Smckusick return (error); 147139896Smckusick if ((long)bp->b_blkno == -1) 147239674Smckusick clrbuf(bp); 147339674Smckusick } 147439896Smckusick if ((long)bp->b_blkno == -1) { 147539896Smckusick biodone(bp); 147639674Smckusick return (0); 147739896Smckusick } 147841538Smckusick #ifdef DIAGNOSTIC 147939674Smckusick if (checkoverlap) { 148041538Smckusick register struct buf *ep; 148141538Smckusick struct buf *ebp; 148241538Smckusick daddr_t start, last; 148341538Smckusick 148439674Smckusick ebp = &buf[nbuf]; 148539674Smckusick start = bp->b_blkno; 148639674Smckusick last = start + btodb(bp->b_bcount) - 1; 148739674Smckusick for (ep = buf; ep < ebp; ep++) { 148839674Smckusick if (ep == bp || (ep->b_flags & B_INVAL) || 148941396Smckusick ep->b_vp == NULLVP) 149039674Smckusick continue; 149139674Smckusick if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0)) 149239674Smckusick continue; 149339674Smckusick if (vp != ip->i_devvp) 149439674Smckusick continue; 149539674Smckusick /* look for overlap */ 149639674Smckusick if (ep->b_bcount == 0 || ep->b_blkno > last || 149739674Smckusick ep->b_blkno + btodb(ep->b_bcount) <= start) 149839674Smckusick continue; 149939896Smckusick vprint("Disk overlap", vp); 150039896Smckusick printf("\tstart %d, end %d overlap start %d, end %d\n", 150139896Smckusick start, last, ep->b_blkno, 150239896Smckusick ep->b_blkno + btodb(ep->b_bcount) - 1); 150341538Smckusick panic("Disk buffer overlap"); 150439674Smckusick } 150539674Smckusick } 150641538Smckusick #endif /* DIAGNOSTIC */ 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; 165541312Smckusick if ((mode & IFMT) == 0) 165641312Smckusick mode |= IFREG; 165737737Smckusick if ((mode & IFMT) == IFDIR) 165837737Smckusick ipref = dirpref(pdir->i_fs); 165937737Smckusick else 166037737Smckusick ipref = pdir->i_number; 166141312Smckusick if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { 166237737Smckusick iput(pdir); 166337737Smckusick return (error); 166437737Smckusick } 166537737Smckusick ip = tip; 166641312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 166741312Smckusick ip->i_gid = pdir->i_gid; 166837737Smckusick #ifdef QUOTA 166941312Smckusick if ((error = getinoquota(ip)) || 167041312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 167141312Smckusick ifree(ip, ip->i_number, mode); 167241312Smckusick iput(ip); 167341312Smckusick iput(pdir); 167441312Smckusick return (error); 167541312Smckusick } 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 */ 168841312Smckusick if (error = iupdat(ip, &time, &time, 1)) 168941312Smckusick goto bad; 169041312Smckusick if (error = direnter(ip, ndp)) { 169141312Smckusick pdir = NULL; 169241312Smckusick goto bad; 169337737Smckusick } 169437737Smckusick *ipp = ip; 169537737Smckusick return (0); 169641312Smckusick 169741312Smckusick bad: 169841312Smckusick /* 169941312Smckusick * Write error occurred trying to update the inode 170041312Smckusick * or the directory so must deallocate the inode. 170141312Smckusick */ 170241312Smckusick if (pdir) 170341312Smckusick iput(pdir); 170441312Smckusick ip->i_nlink = 0; 170541312Smckusick ip->i_flag |= ICHG; 170641312Smckusick iput(ip); 170741312Smckusick return (error); 170837737Smckusick } 1709