123405Smckusick /* 237737Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337737Smckusick * All rights reserved. 423405Smckusick * 544539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*47571Skarels * @(#)lfs_vnops.c 7.58 (Berkeley) 03/19/91 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 12*47571Skarels #include "namei.h" 13*47571Skarels #include "resourcevar.h" 1417101Sbloom #include "kernel.h" 1517101Sbloom #include "file.h" 1617101Sbloom #include "stat.h" 1717101Sbloom #include "buf.h" 1817101Sbloom #include "proc.h" 1937737Smckusick #include "conf.h" 2017101Sbloom #include "mount.h" 2137737Smckusick #include "vnode.h" 2240653Smckusick #include "specdev.h" 2346207Smckusick #include "fcntl.h" 2446207Smckusick #include "malloc.h" 2537Sbill 26*47571Skarels #include "lockf.h" 27*47571Skarels #include "quota.h" 28*47571Skarels #include "inode.h" 29*47571Skarels #include "fs.h" 30*47571Skarels 319167Ssam /* 3237737Smckusick * Global vfs data structures for ufs 339167Ssam */ 346254Sroot 3537737Smckusick int ufs_lookup(), 3637737Smckusick ufs_create(), 3737737Smckusick ufs_mknod(), 3837737Smckusick ufs_open(), 3937737Smckusick ufs_close(), 4037737Smckusick ufs_access(), 4137737Smckusick ufs_getattr(), 4237737Smckusick ufs_setattr(), 4337737Smckusick ufs_read(), 4437737Smckusick ufs_write(), 4537737Smckusick ufs_ioctl(), 4637737Smckusick ufs_select(), 4737737Smckusick ufs_mmap(), 4837737Smckusick ufs_fsync(), 4937737Smckusick ufs_seek(), 5037737Smckusick ufs_remove(), 5137737Smckusick ufs_link(), 5237737Smckusick ufs_rename(), 5337737Smckusick ufs_mkdir(), 5437737Smckusick ufs_rmdir(), 5537737Smckusick ufs_symlink(), 5637737Smckusick ufs_readdir(), 5737737Smckusick ufs_readlink(), 5837737Smckusick ufs_abortop(), 5937737Smckusick ufs_inactive(), 6039391Smckusick ufs_reclaim(), 6137737Smckusick ufs_lock(), 6237737Smckusick ufs_unlock(), 6337737Smckusick ufs_bmap(), 6439674Smckusick ufs_strategy(), 6539909Smckusick ufs_print(), 6646207Smckusick ufs_islocked(), 6746207Smckusick ufs_advlock(); 686254Sroot 6937737Smckusick struct vnodeops ufs_vnodeops = { 7039674Smckusick ufs_lookup, /* lookup */ 7139674Smckusick ufs_create, /* create */ 7239674Smckusick ufs_mknod, /* mknod */ 7339674Smckusick ufs_open, /* open */ 7439674Smckusick ufs_close, /* close */ 7539674Smckusick ufs_access, /* access */ 7639674Smckusick ufs_getattr, /* getattr */ 7739674Smckusick ufs_setattr, /* setattr */ 7839674Smckusick ufs_read, /* read */ 7939674Smckusick ufs_write, /* write */ 8039674Smckusick ufs_ioctl, /* ioctl */ 8139674Smckusick ufs_select, /* select */ 8239674Smckusick ufs_mmap, /* mmap */ 8339674Smckusick ufs_fsync, /* fsync */ 8439674Smckusick ufs_seek, /* seek */ 8539674Smckusick ufs_remove, /* remove */ 8639674Smckusick ufs_link, /* link */ 8739674Smckusick ufs_rename, /* rename */ 8839674Smckusick ufs_mkdir, /* mkdir */ 8939674Smckusick ufs_rmdir, /* rmdir */ 9039674Smckusick ufs_symlink, /* symlink */ 9139674Smckusick ufs_readdir, /* readdir */ 9239674Smckusick ufs_readlink, /* readlink */ 9339674Smckusick ufs_abortop, /* abortop */ 9439674Smckusick ufs_inactive, /* inactive */ 9539674Smckusick ufs_reclaim, /* reclaim */ 9639674Smckusick ufs_lock, /* lock */ 9739674Smckusick ufs_unlock, /* unlock */ 9839674Smckusick ufs_bmap, /* bmap */ 9939674Smckusick ufs_strategy, /* strategy */ 10039674Smckusick ufs_print, /* print */ 10139909Smckusick ufs_islocked, /* islocked */ 10246207Smckusick ufs_advlock, /* advlock */ 10337737Smckusick }; 1046254Sroot 10539435Smckusick int spec_lookup(), 10639435Smckusick spec_open(), 10739628Smckusick ufsspec_read(), 10839628Smckusick ufsspec_write(), 10939435Smckusick spec_strategy(), 11039674Smckusick spec_bmap(), 11139435Smckusick spec_ioctl(), 11239435Smckusick spec_select(), 11339628Smckusick ufsspec_close(), 11446207Smckusick spec_advlock(), 115*47571Skarels spec_badop(); 11639435Smckusick 11739435Smckusick struct vnodeops spec_inodeops = { 11839597Smckusick spec_lookup, /* lookup */ 11939597Smckusick spec_badop, /* create */ 12039597Smckusick spec_badop, /* mknod */ 12139597Smckusick spec_open, /* open */ 12239628Smckusick ufsspec_close, /* close */ 12339597Smckusick ufs_access, /* access */ 12439597Smckusick ufs_getattr, /* getattr */ 12539597Smckusick ufs_setattr, /* setattr */ 12639628Smckusick ufsspec_read, /* read */ 12739628Smckusick ufsspec_write, /* write */ 12839597Smckusick spec_ioctl, /* ioctl */ 12939597Smckusick spec_select, /* select */ 13039597Smckusick spec_badop, /* mmap */ 13146679Smckusick nullop, /* fsync */ 13239597Smckusick spec_badop, /* seek */ 13339597Smckusick spec_badop, /* remove */ 13439597Smckusick spec_badop, /* link */ 13539597Smckusick spec_badop, /* rename */ 13639597Smckusick spec_badop, /* mkdir */ 13739597Smckusick spec_badop, /* rmdir */ 13839597Smckusick spec_badop, /* symlink */ 13939597Smckusick spec_badop, /* readdir */ 14039597Smckusick spec_badop, /* readlink */ 14139597Smckusick spec_badop, /* abortop */ 14239597Smckusick ufs_inactive, /* inactive */ 14339597Smckusick ufs_reclaim, /* reclaim */ 14439597Smckusick ufs_lock, /* lock */ 14539597Smckusick ufs_unlock, /* unlock */ 14639674Smckusick spec_bmap, /* bmap */ 14739597Smckusick spec_strategy, /* strategy */ 14839674Smckusick ufs_print, /* print */ 14939909Smckusick ufs_islocked, /* islocked */ 15046207Smckusick spec_advlock, /* advlock */ 15139435Smckusick }; 15239435Smckusick 15340290Smckusick #ifdef FIFO 15440290Smckusick int fifo_lookup(), 15540290Smckusick fifo_open(), 15640290Smckusick ufsfifo_read(), 15740290Smckusick ufsfifo_write(), 15840290Smckusick fifo_bmap(), 15940290Smckusick fifo_ioctl(), 16040290Smckusick fifo_select(), 16140290Smckusick ufsfifo_close(), 16240290Smckusick fifo_print(), 16346207Smckusick fifo_advlock(), 16446679Smckusick fifo_badop(); 16540290Smckusick 16640290Smckusick struct vnodeops fifo_inodeops = { 16740290Smckusick fifo_lookup, /* lookup */ 16840290Smckusick fifo_badop, /* create */ 16940290Smckusick fifo_badop, /* mknod */ 17040290Smckusick fifo_open, /* open */ 17140290Smckusick ufsfifo_close, /* close */ 17240290Smckusick ufs_access, /* access */ 17340290Smckusick ufs_getattr, /* getattr */ 17440290Smckusick ufs_setattr, /* setattr */ 17540290Smckusick ufsfifo_read, /* read */ 17640290Smckusick ufsfifo_write, /* write */ 17740290Smckusick fifo_ioctl, /* ioctl */ 17840290Smckusick fifo_select, /* select */ 17940290Smckusick fifo_badop, /* mmap */ 18046679Smckusick nullop, /* fsync */ 18140290Smckusick fifo_badop, /* seek */ 18240290Smckusick fifo_badop, /* remove */ 18340290Smckusick fifo_badop, /* link */ 18440290Smckusick fifo_badop, /* rename */ 18540290Smckusick fifo_badop, /* mkdir */ 18640290Smckusick fifo_badop, /* rmdir */ 18740290Smckusick fifo_badop, /* symlink */ 18840290Smckusick fifo_badop, /* readdir */ 18940290Smckusick fifo_badop, /* readlink */ 19040290Smckusick fifo_badop, /* abortop */ 19140290Smckusick ufs_inactive, /* inactive */ 19240290Smckusick ufs_reclaim, /* reclaim */ 19340290Smckusick ufs_lock, /* lock */ 19440290Smckusick ufs_unlock, /* unlock */ 19540290Smckusick fifo_bmap, /* bmap */ 19640290Smckusick fifo_badop, /* strategy */ 19740290Smckusick ufs_print, /* print */ 19840290Smckusick ufs_islocked, /* islocked */ 19946207Smckusick fifo_advlock, /* advlock */ 20037737Smckusick }; 20140290Smckusick #endif /* FIFO */ 20240290Smckusick 20340290Smckusick enum vtype iftovt_tab[16] = { 20440290Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 20540290Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 20637737Smckusick }; 20740290Smckusick int vttoif_tab[9] = { 20840290Smckusick 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT, 20940290Smckusick }; 2106254Sroot 2119167Ssam /* 21237737Smckusick * Create a regular file 2139167Ssam */ 21437737Smckusick ufs_create(ndp, vap) 21537737Smckusick struct nameidata *ndp; 21637737Smckusick struct vattr *vap; 2176254Sroot { 21837737Smckusick struct inode *ip; 21937737Smckusick int error; 2206254Sroot 22137737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 22237737Smckusick return (error); 22337737Smckusick ndp->ni_vp = ITOV(ip); 22437737Smckusick return (0); 2256254Sroot } 2266254Sroot 22737Sbill /* 22837737Smckusick * Mknod vnode call 2296254Sroot */ 23037737Smckusick /* ARGSUSED */ 23137737Smckusick ufs_mknod(ndp, vap, cred) 23237737Smckusick struct nameidata *ndp; 23337737Smckusick struct ucred *cred; 23437737Smckusick struct vattr *vap; 2356254Sroot { 23639435Smckusick register struct vnode *vp; 23737737Smckusick struct inode *ip; 23837737Smckusick int error; 2396254Sroot 24037737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 24137737Smckusick return (error); 24240290Smckusick ip->i_flag |= IACC|IUPD|ICHG; 24340290Smckusick if (vap->va_rdev != VNOVAL) { 24437737Smckusick /* 24537737Smckusick * Want to be able to use this to make badblock 24637737Smckusick * inodes, so don't truncate the dev number. 24737737Smckusick */ 24839608Smckusick ip->i_rdev = vap->va_rdev; 24912756Ssam } 25037737Smckusick /* 25137737Smckusick * Remove inode so that it will be reloaded by iget and 25237737Smckusick * checked to see if it is an alias of an existing entry 25337737Smckusick * in the inode cache. 25437737Smckusick */ 25540290Smckusick vp = ITOV(ip); 25640290Smckusick vput(vp); 25739435Smckusick vp->v_type = VNON; 25839435Smckusick vgone(vp); 25937737Smckusick return (0); 2606254Sroot } 2616254Sroot 2626254Sroot /* 26337737Smckusick * Open called. 26437737Smckusick * 26537737Smckusick * Nothing to do. 2666254Sroot */ 26737737Smckusick /* ARGSUSED */ 26837737Smckusick ufs_open(vp, mode, cred) 26937737Smckusick struct vnode *vp; 27037737Smckusick int mode; 27137737Smckusick struct ucred *cred; 2726254Sroot { 2736254Sroot 27437737Smckusick return (0); 2756254Sroot } 2766254Sroot 2776254Sroot /* 27837737Smckusick * Close called 27937737Smckusick * 28037737Smckusick * Update the times on the inode. 2816254Sroot */ 28237737Smckusick /* ARGSUSED */ 28337737Smckusick ufs_close(vp, fflag, cred) 28437737Smckusick struct vnode *vp; 28537737Smckusick int fflag; 28637737Smckusick struct ucred *cred; 2876254Sroot { 28837737Smckusick register struct inode *ip = VTOI(vp); 2896254Sroot 29039815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 29137737Smckusick ITIMES(ip, &time, &time); 29237737Smckusick return (0); 2936254Sroot } 2946254Sroot 29541312Smckusick /* 29641312Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 29741312Smckusick * The mode is shifted to select the owner/group/other fields. The 29841312Smckusick * super user is granted all permissions. 29941312Smckusick */ 30037737Smckusick ufs_access(vp, mode, cred) 30137737Smckusick struct vnode *vp; 30241312Smckusick register int mode; 30337737Smckusick struct ucred *cred; 3046254Sroot { 30541312Smckusick register struct inode *ip = VTOI(vp); 30641312Smckusick register gid_t *gp; 30741312Smckusick int i, error; 3086254Sroot 30941312Smckusick #ifdef DIAGNOSTIC 31041312Smckusick if (!VOP_ISLOCKED(vp)) { 31141312Smckusick vprint("ufs_access: not locked", vp); 31241312Smckusick panic("ufs_access: not locked"); 31341312Smckusick } 31441312Smckusick #endif 31541312Smckusick #ifdef QUOTA 31641312Smckusick if (mode & VWRITE) { 31741312Smckusick switch (vp->v_type) { 31841312Smckusick case VREG: case VDIR: case VLNK: 31941312Smckusick if (error = getinoquota(ip)) 32041312Smckusick return (error); 32141312Smckusick } 32241312Smckusick } 32341312Smckusick #endif /* QUOTA */ 32441312Smckusick /* 32541312Smckusick * If you're the super-user, you always get access. 32641312Smckusick */ 32741312Smckusick if (cred->cr_uid == 0) 32841312Smckusick return (0); 32941312Smckusick /* 33041312Smckusick * Access check is based on only one of owner, group, public. 33141312Smckusick * If not owner, then check group. If not a member of the 33241312Smckusick * group, then check public access. 33341312Smckusick */ 33441312Smckusick if (cred->cr_uid != ip->i_uid) { 33541312Smckusick mode >>= 3; 33641312Smckusick gp = cred->cr_groups; 33741312Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 33841312Smckusick if (ip->i_gid == *gp) 33941312Smckusick goto found; 34041312Smckusick mode >>= 3; 34141312Smckusick found: 34241312Smckusick ; 34341312Smckusick } 34441312Smckusick if ((ip->i_mode & mode) != 0) 34541312Smckusick return (0); 34641312Smckusick return (EACCES); 3476254Sroot } 3486254Sroot 34937737Smckusick /* ARGSUSED */ 35037737Smckusick ufs_getattr(vp, vap, cred) 35137737Smckusick struct vnode *vp; 35237737Smckusick register struct vattr *vap; 35337737Smckusick struct ucred *cred; 3546254Sroot { 35537737Smckusick register struct inode *ip = VTOI(vp); 3566254Sroot 35737737Smckusick ITIMES(ip, &time, &time); 3586254Sroot /* 35937737Smckusick * Copy from inode table 3606254Sroot */ 36137737Smckusick vap->va_fsid = ip->i_dev; 36237737Smckusick vap->va_fileid = ip->i_number; 36337737Smckusick vap->va_mode = ip->i_mode & ~IFMT; 36437737Smckusick vap->va_nlink = ip->i_nlink; 36537737Smckusick vap->va_uid = ip->i_uid; 36637737Smckusick vap->va_gid = ip->i_gid; 36737737Smckusick vap->va_rdev = (dev_t)ip->i_rdev; 36841312Smckusick #ifdef tahoe 36941312Smckusick vap->va_size = ip->i_size; 37041312Smckusick vap->va_size_rsv = 0; 37141312Smckusick #else 37240641Smckusick vap->va_qsize = ip->i_din.di_qsize; 37341312Smckusick #endif 37437737Smckusick vap->va_atime.tv_sec = ip->i_atime; 37538578Smckusick vap->va_atime.tv_usec = 0; 37637737Smckusick vap->va_mtime.tv_sec = ip->i_mtime; 37738578Smckusick vap->va_mtime.tv_usec = 0; 37837737Smckusick vap->va_ctime.tv_sec = ip->i_ctime; 37938578Smckusick vap->va_ctime.tv_usec = 0; 38038254Smckusick vap->va_flags = ip->i_flags; 38138254Smckusick vap->va_gen = ip->i_gen; 38237737Smckusick /* this doesn't belong here */ 38337737Smckusick if (vp->v_type == VBLK) 38437737Smckusick vap->va_blocksize = BLKDEV_IOSIZE; 38537737Smckusick else if (vp->v_type == VCHR) 38637737Smckusick vap->va_blocksize = MAXBSIZE; 3877142Smckusick else 38837737Smckusick vap->va_blocksize = ip->i_fs->fs_bsize; 38938657Smckusick vap->va_bytes = dbtob(ip->i_blocks); 39040641Smckusick vap->va_bytes_rsv = 0; 39137737Smckusick vap->va_type = vp->v_type; 39237737Smckusick return (0); 3936254Sroot } 3946254Sroot 3956254Sroot /* 39637737Smckusick * Set attribute vnode op. called from several syscalls 3976254Sroot */ 39837737Smckusick ufs_setattr(vp, vap, cred) 39937737Smckusick register struct vnode *vp; 40037737Smckusick register struct vattr *vap; 40137737Smckusick register struct ucred *cred; 4026254Sroot { 403*47571Skarels struct proc *p = curproc; /* XXX */ 40437737Smckusick register struct inode *ip = VTOI(vp); 40537737Smckusick int error = 0; 4066254Sroot 40737737Smckusick /* 40837737Smckusick * Check for unsetable attributes. 40937737Smckusick */ 41037737Smckusick if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 41137737Smckusick (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 41237737Smckusick (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 41338254Smckusick ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 41437737Smckusick return (EINVAL); 41516540Ssam } 41637737Smckusick /* 41737737Smckusick * Go through the fields and update iff not VNOVAL. 41837737Smckusick */ 41937737Smckusick if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) 420*47571Skarels if (error = chown1(vp, vap->va_uid, vap->va_gid, p)) 42137737Smckusick return (error); 42237737Smckusick if (vap->va_size != VNOVAL) { 42337737Smckusick if (vp->v_type == VDIR) 42437737Smckusick return (EISDIR); 42539674Smckusick if (error = itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */ 42637737Smckusick return (error); 42713878Ssam } 42837737Smckusick if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 42937773Smckusick if (cred->cr_uid != ip->i_uid && 430*47571Skarels (error = suser(cred, &p->p_acflag))) 43137773Smckusick return (error); 43237737Smckusick if (vap->va_atime.tv_sec != VNOVAL) 43337737Smckusick ip->i_flag |= IACC; 43437737Smckusick if (vap->va_mtime.tv_sec != VNOVAL) 43537737Smckusick ip->i_flag |= IUPD; 43637737Smckusick ip->i_flag |= ICHG; 43737737Smckusick if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) 43837737Smckusick return (error); 4396254Sroot } 44037737Smckusick if (vap->va_mode != (u_short)VNOVAL) 441*47571Skarels error = chmod1(vp, (int)vap->va_mode, p); 44238254Smckusick if (vap->va_flags != VNOVAL) { 44338254Smckusick if (cred->cr_uid != ip->i_uid && 444*47571Skarels (error = suser(cred, &p->p_acflag))) 44538254Smckusick return (error); 44638254Smckusick if (cred->cr_uid == 0) { 44738254Smckusick ip->i_flags = vap->va_flags; 44838254Smckusick } else { 44938254Smckusick ip->i_flags &= 0xffff0000; 45038254Smckusick ip->i_flags |= (vap->va_flags & 0xffff); 45138254Smckusick } 45238254Smckusick ip->i_flag |= ICHG; 45338254Smckusick } 45437737Smckusick return (error); 4556254Sroot } 4566254Sroot 4576254Sroot /* 4589167Ssam * Change the mode on a file. 4599167Ssam * Inode must be locked before calling. 4609167Ssam */ 461*47571Skarels chmod1(vp, mode, p) 46237737Smckusick register struct vnode *vp; 4637701Ssam register int mode; 464*47571Skarels struct proc *p; 4657701Ssam { 466*47571Skarels register struct ucred *cred = p->p_ucred; 46737737Smckusick register struct inode *ip = VTOI(vp); 46837773Smckusick int error; 4697868Sroot 47037773Smckusick if (cred->cr_uid != ip->i_uid && 471*47571Skarels (error = suser(cred, &p->p_acflag))) 47237773Smckusick return (error); 47337737Smckusick if (cred->cr_uid) { 47446206Smckusick if (vp->v_type != VDIR && (mode & ISVTX)) 47545783Sbostic return (EFTYPE); 47646206Smckusick if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) 47745783Sbostic return (EPERM); 4787439Sroot } 47945783Sbostic ip->i_mode &= ~07777; 48037737Smckusick ip->i_mode |= mode & 07777; 4816254Sroot ip->i_flag |= ICHG; 48237737Smckusick if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) 48345722Smckusick (void) vnode_pager_uncache(vp); 48421015Smckusick return (0); 4855992Swnj } 4865992Swnj 4879167Ssam /* 4887701Ssam * Perform chown operation on inode ip; 4897701Ssam * inode must be locked prior to call. 4907701Ssam */ 491*47571Skarels chown1(vp, uid, gid, p) 49237737Smckusick register struct vnode *vp; 49337737Smckusick uid_t uid; 49437737Smckusick gid_t gid; 495*47571Skarels struct proc *p; 4967701Ssam { 49737737Smckusick register struct inode *ip = VTOI(vp); 498*47571Skarels register struct ucred *cred = p->p_ucred; 49941312Smckusick uid_t ouid; 50041312Smckusick gid_t ogid; 50141312Smckusick int error = 0; 5027701Ssam #ifdef QUOTA 50341312Smckusick register int i; 50441312Smckusick 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)) && 518*47571Skarels (error = suser(cred, &p->p_acflag))) 51937737Smckusick return (error); 52041312Smckusick ouid = ip->i_uid; 52141312Smckusick ogid = ip->i_gid; 52211811Ssam #ifdef QUOTA 52341312Smckusick if (error = getinoquota(ip)) 52441312Smckusick return (error); 52541312Smckusick if (ouid == uid) { 52641312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 52741312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 52841312Smckusick } 52941312Smckusick if (ogid == gid) { 53041312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 53141312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 53241312Smckusick } 53341312Smckusick change = ip->i_blocks; 53441312Smckusick (void) chkdq(ip, -change, cred, CHOWN); 53541312Smckusick (void) chkiq(ip, -1, cred, CHOWN); 53641312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 53741312Smckusick dqrele(vp, ip->i_dquot[i]); 53841312Smckusick ip->i_dquot[i] = NODQUOT; 53941312Smckusick } 5407482Skre #endif 54111811Ssam ip->i_uid = uid; 54211811Ssam ip->i_gid = gid; 5437701Ssam #ifdef QUOTA 54441312Smckusick if ((error = getinoquota(ip)) == 0) { 54541312Smckusick if (ouid == uid) { 54641312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 54741312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 54841312Smckusick } 54941312Smckusick if (ogid == gid) { 55041312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 55141312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 55241312Smckusick } 55341312Smckusick if ((error = chkdq(ip, change, cred, CHOWN)) == 0) { 55441312Smckusick if ((error = chkiq(ip, 1, cred, CHOWN)) == 0) 55541927Smckusick goto good; 55641312Smckusick else 55741312Smckusick (void) chkdq(ip, -change, cred, CHOWN|FORCE); 55841312Smckusick } 55941312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 56041312Smckusick dqrele(vp, ip->i_dquot[i]); 56141312Smckusick ip->i_dquot[i] = NODQUOT; 56241312Smckusick } 56341312Smckusick } 56441312Smckusick ip->i_uid = ouid; 56541312Smckusick ip->i_gid = ogid; 56641312Smckusick if (getinoquota(ip) == 0) { 56741312Smckusick if (ouid == uid) { 56841312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 56941312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 57041312Smckusick } 57141312Smckusick if (ogid == gid) { 57241312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 57341312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 57441312Smckusick } 57541927Smckusick (void) chkdq(ip, change, cred, FORCE|CHOWN); 57641927Smckusick (void) chkiq(ip, 1, cred, FORCE|CHOWN); 57742440Smckusick (void) getinoquota(ip); 57841312Smckusick } 57942440Smckusick return (error); 58041927Smckusick good: 58142440Smckusick if (getinoquota(ip)) 58242440Smckusick panic("chown: lost quota"); 58342440Smckusick #endif /* QUOTA */ 58441312Smckusick if (ouid != uid || ogid != gid) 58541312Smckusick ip->i_flag |= ICHG; 58641312Smckusick if (ouid != uid && cred->cr_uid != 0) 58741312Smckusick ip->i_mode &= ~ISUID; 58841312Smckusick if (ogid != gid && cred->cr_uid != 0) 58941312Smckusick ip->i_mode &= ~ISGID; 59012646Ssam return (0); 59137Sbill } 59237Sbill 59339608Smckusick /* 59439608Smckusick * Vnode op for reading. 59539608Smckusick */ 59637737Smckusick /* ARGSUSED */ 59739608Smckusick ufs_read(vp, uio, ioflag, cred) 59839608Smckusick struct vnode *vp; 59939608Smckusick register struct uio *uio; 60039608Smckusick int ioflag; 60139608Smckusick struct ucred *cred; 60239608Smckusick { 60339608Smckusick register struct inode *ip = VTOI(vp); 60439608Smckusick register struct fs *fs; 60539608Smckusick struct buf *bp; 60639608Smckusick daddr_t lbn, bn, rablock; 60739896Smckusick int size, diff, error = 0; 60839608Smckusick long n, on, type; 60939608Smckusick 61039608Smckusick if (uio->uio_rw != UIO_READ) 61139608Smckusick panic("ufs_read mode"); 61239608Smckusick type = ip->i_mode & IFMT; 61339608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 61439608Smckusick panic("ufs_read type"); 61539608Smckusick if (uio->uio_resid == 0) 61639608Smckusick return (0); 61739608Smckusick if (uio->uio_offset < 0) 61839608Smckusick return (EINVAL); 61939608Smckusick ip->i_flag |= IACC; 62039608Smckusick fs = ip->i_fs; 62139608Smckusick do { 62239608Smckusick lbn = lblkno(fs, uio->uio_offset); 62339608Smckusick on = blkoff(fs, uio->uio_offset); 62439608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 62539608Smckusick diff = ip->i_size - uio->uio_offset; 62639608Smckusick if (diff <= 0) 62739608Smckusick return (0); 62839608Smckusick if (diff < n) 62939608Smckusick n = diff; 63039608Smckusick size = blksize(fs, ip, lbn); 63139674Smckusick rablock = lbn + 1; 63239896Smckusick if (vp->v_lastr + 1 == lbn && 63339896Smckusick lblktosize(fs, rablock) < ip->i_size) 63439896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 63539896Smckusick blksize(fs, ip, rablock), NOCRED, &bp); 63639608Smckusick else 63739674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 63839815Smckusick vp->v_lastr = lbn; 63939608Smckusick n = MIN(n, size - bp->b_resid); 64039608Smckusick if (error) { 64139608Smckusick brelse(bp); 64239608Smckusick return (error); 64339608Smckusick } 64439608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 64539608Smckusick if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size) 64639608Smckusick bp->b_flags |= B_AGE; 64739608Smckusick brelse(bp); 64839608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 64939608Smckusick return (error); 65039608Smckusick } 65139608Smckusick 65239608Smckusick /* 65339608Smckusick * Vnode op for writing. 65439608Smckusick */ 65539608Smckusick ufs_write(vp, uio, ioflag, cred) 65639608Smckusick register struct vnode *vp; 65739608Smckusick struct uio *uio; 65839608Smckusick int ioflag; 65939608Smckusick struct ucred *cred; 66039608Smckusick { 661*47571Skarels struct proc *p = curproc; /* XXX */ 66239608Smckusick register struct inode *ip = VTOI(vp); 66339608Smckusick register struct fs *fs; 66439608Smckusick struct buf *bp; 66539608Smckusick daddr_t lbn, bn; 66639608Smckusick u_long osize; 66745722Smckusick int n, on, flags; 66845722Smckusick int size, resid, error = 0; 66939608Smckusick 67039608Smckusick if (uio->uio_rw != UIO_WRITE) 67139608Smckusick panic("ufs_write mode"); 67239608Smckusick switch (vp->v_type) { 67339608Smckusick case VREG: 67439608Smckusick if (ioflag & IO_APPEND) 67539608Smckusick uio->uio_offset = ip->i_size; 67639608Smckusick /* fall through */ 67739608Smckusick case VLNK: 67839608Smckusick break; 67939608Smckusick 68039608Smckusick case VDIR: 68139608Smckusick if ((ioflag & IO_SYNC) == 0) 68239608Smckusick panic("ufs_write nonsync dir write"); 68339608Smckusick break; 68439608Smckusick 68539608Smckusick default: 68639608Smckusick panic("ufs_write type"); 68739608Smckusick } 68839608Smckusick if (uio->uio_offset < 0) 68939608Smckusick return (EINVAL); 69039608Smckusick if (uio->uio_resid == 0) 69139608Smckusick return (0); 69239608Smckusick /* 69339608Smckusick * Maybe this should be above the vnode op call, but so long as 69439608Smckusick * file servers have no limits, i don't think it matters 69539608Smckusick */ 69639608Smckusick if (vp->v_type == VREG && 69739608Smckusick uio->uio_offset + uio->uio_resid > 698*47571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 699*47571Skarels psignal(p, SIGXFSZ); 70039608Smckusick return (EFBIG); 70139608Smckusick } 70239608Smckusick resid = uio->uio_resid; 70339608Smckusick osize = ip->i_size; 70439608Smckusick fs = ip->i_fs; 70539674Smckusick flags = 0; 70639674Smckusick if (ioflag & IO_SYNC) 70739674Smckusick flags = B_SYNC; 70839608Smckusick do { 70939608Smckusick lbn = lblkno(fs, uio->uio_offset); 71039608Smckusick on = blkoff(fs, uio->uio_offset); 71139608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 71239608Smckusick if (n < fs->fs_bsize) 71339674Smckusick flags |= B_CLRBUF; 71439608Smckusick else 71539674Smckusick flags &= ~B_CLRBUF; 71639674Smckusick if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) 71739608Smckusick break; 71839674Smckusick bn = bp->b_blkno; 71945722Smckusick if (uio->uio_offset + n > ip->i_size) { 72039608Smckusick ip->i_size = uio->uio_offset + n; 72145722Smckusick vnode_pager_setsize(vp, ip->i_size); 72245722Smckusick } 72339608Smckusick size = blksize(fs, ip, lbn); 72445722Smckusick (void) vnode_pager_uncache(vp); 72539608Smckusick n = MIN(n, size - bp->b_resid); 72639608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 72739608Smckusick if (ioflag & IO_SYNC) 72839608Smckusick (void) bwrite(bp); 72939608Smckusick else if (n + on == fs->fs_bsize) { 73039608Smckusick bp->b_flags |= B_AGE; 73139608Smckusick bawrite(bp); 73239608Smckusick } else 73339608Smckusick bdwrite(bp); 73439608Smckusick ip->i_flag |= IUPD|ICHG; 73539608Smckusick if (cred->cr_uid != 0) 73639608Smckusick ip->i_mode &= ~(ISUID|ISGID); 73739608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 73839608Smckusick if (error && (ioflag & IO_UNIT)) { 73939674Smckusick (void) itrunc(ip, osize, ioflag & IO_SYNC); 74039608Smckusick uio->uio_offset -= resid - uio->uio_resid; 74139608Smckusick uio->uio_resid = resid; 74239608Smckusick } 74342493Smckusick if (!error && (ioflag & IO_SYNC)) 74442493Smckusick error = iupdat(ip, &time, &time, 1); 74539608Smckusick return (error); 74639608Smckusick } 74739608Smckusick 74839608Smckusick /* ARGSUSED */ 74937737Smckusick ufs_ioctl(vp, com, data, fflag, cred) 75037737Smckusick struct vnode *vp; 75137737Smckusick int com; 75237737Smckusick caddr_t data; 75337737Smckusick int fflag; 75437737Smckusick struct ucred *cred; 75511811Ssam { 75611811Ssam 75737737Smckusick return (ENOTTY); 75811811Ssam } 75911811Ssam 76037737Smckusick /* ARGSUSED */ 76140290Smckusick ufs_select(vp, which, fflags, cred) 76237737Smckusick struct vnode *vp; 76340290Smckusick int which, fflags; 76437737Smckusick struct ucred *cred; 76537737Smckusick { 76637737Smckusick 76737737Smckusick return (1); /* XXX */ 76837737Smckusick } 76937737Smckusick 7709167Ssam /* 77137737Smckusick * Mmap a file 77237737Smckusick * 77337737Smckusick * NB Currently unsupported. 7749167Ssam */ 77537737Smckusick /* ARGSUSED */ 77637737Smckusick ufs_mmap(vp, fflags, cred) 77737737Smckusick struct vnode *vp; 77837737Smckusick int fflags; 77937737Smckusick struct ucred *cred; 78037Sbill { 78137Sbill 78237737Smckusick return (EINVAL); 78337Sbill } 7847535Sroot 7859167Ssam /* 78637737Smckusick * Synch an open file. 7879167Ssam */ 78837737Smckusick /* ARGSUSED */ 78939597Smckusick ufs_fsync(vp, fflags, cred, waitfor) 79037737Smckusick struct vnode *vp; 79137737Smckusick int fflags; 79237737Smckusick struct ucred *cred; 79339597Smckusick int waitfor; 7947701Ssam { 79539597Smckusick struct inode *ip = VTOI(vp); 7967701Ssam 79737737Smckusick if (fflags&FWRITE) 79837737Smckusick ip->i_flag |= ICHG; 79939674Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 80039674Smckusick return (iupdat(ip, &time, &time, waitfor == MNT_WAIT)); 8017701Ssam } 8027701Ssam 8039167Ssam /* 80437737Smckusick * Seek on a file 80537737Smckusick * 80637737Smckusick * Nothing to do, so just return. 8079167Ssam */ 80837737Smckusick /* ARGSUSED */ 80937737Smckusick ufs_seek(vp, oldoff, newoff, cred) 81037737Smckusick struct vnode *vp; 81137737Smckusick off_t oldoff, newoff; 81237737Smckusick struct ucred *cred; 8137701Ssam { 8147701Ssam 81537737Smckusick return (0); 81637737Smckusick } 81737737Smckusick 81837737Smckusick /* 81937737Smckusick * ufs remove 82037737Smckusick * Hard to avoid races here, especially 82137737Smckusick * in unlinking directories. 82237737Smckusick */ 82337737Smckusick ufs_remove(ndp) 82437737Smckusick struct nameidata *ndp; 82537737Smckusick { 82637737Smckusick register struct inode *ip, *dp; 82737737Smckusick int error; 82837737Smckusick 82937737Smckusick ip = VTOI(ndp->ni_vp); 83037737Smckusick dp = VTOI(ndp->ni_dvp); 83137737Smckusick error = dirremove(ndp); 83237737Smckusick if (!error) { 83337737Smckusick ip->i_nlink--; 83437737Smckusick ip->i_flag |= ICHG; 8357701Ssam } 83637737Smckusick if (dp == ip) 83737737Smckusick vrele(ITOV(ip)); 83837737Smckusick else 83937737Smckusick iput(ip); 84037737Smckusick iput(dp); 84137737Smckusick return (error); 8427701Ssam } 8437701Ssam 8449167Ssam /* 84537737Smckusick * link vnode call 8469167Ssam */ 84737737Smckusick ufs_link(vp, ndp) 84837737Smckusick register struct vnode *vp; 84937737Smckusick register struct nameidata *ndp; 8509167Ssam { 85137737Smckusick register struct inode *ip = VTOI(vp); 85237737Smckusick int error; 8539167Ssam 85446251Smckusick if ((unsigned short)ip->i_nlink >= LINK_MAX) 85546251Smckusick return (EMLINK); 85637737Smckusick if (ndp->ni_dvp != vp) 85737737Smckusick ILOCK(ip); 85837737Smckusick ip->i_nlink++; 85937737Smckusick ip->i_flag |= ICHG; 86037737Smckusick error = iupdat(ip, &time, &time, 1); 86137737Smckusick if (!error) 86237737Smckusick error = direnter(ip, ndp); 86337737Smckusick if (ndp->ni_dvp != vp) 86437737Smckusick IUNLOCK(ip); 86547219Smckusick vput(ndp->ni_dvp); 86637737Smckusick if (error) { 86737737Smckusick ip->i_nlink--; 86830598Smckusick ip->i_flag |= ICHG; 86937737Smckusick } 87037737Smckusick return (error); 8719167Ssam } 8729167Ssam 8739167Ssam /* 8749167Ssam * Rename system call. 8759167Ssam * rename("foo", "bar"); 8769167Ssam * is essentially 8779167Ssam * unlink("bar"); 8789167Ssam * link("foo", "bar"); 8799167Ssam * unlink("foo"); 8809167Ssam * but ``atomically''. Can't do full commit without saving state in the 8819167Ssam * inode on disk which isn't feasible at this time. Best we can do is 8829167Ssam * always guarantee the target exists. 8839167Ssam * 8849167Ssam * Basic algorithm is: 8859167Ssam * 8869167Ssam * 1) Bump link count on source while we're linking it to the 88737737Smckusick * target. This also ensure the inode won't be deleted out 88816776Smckusick * from underneath us while we work (it may be truncated by 88916776Smckusick * a concurrent `trunc' or `open' for creation). 8909167Ssam * 2) Link source to destination. If destination already exists, 8919167Ssam * delete it first. 89216776Smckusick * 3) Unlink source reference to inode if still around. If a 89316776Smckusick * directory was moved and the parent of the destination 8949167Ssam * is different from the source, patch the ".." entry in the 8959167Ssam * directory. 8969167Ssam */ 89737737Smckusick ufs_rename(fndp, tndp) 89837737Smckusick register struct nameidata *fndp, *tndp; 8997701Ssam { 900*47571Skarels struct proc *p = curproc; /* XXX */ 9019167Ssam register struct inode *ip, *xp, *dp; 90216776Smckusick struct dirtemplate dirbuf; 90316776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 90410051Ssam int error = 0; 9057701Ssam 90637737Smckusick dp = VTOI(fndp->ni_dvp); 90737737Smckusick ip = VTOI(fndp->ni_vp); 90837737Smckusick ILOCK(ip); 9099167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 91037737Smckusick register struct direct *d = &fndp->ni_dent; 9119167Ssam 9129167Ssam /* 91311641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 9149167Ssam */ 91537737Smckusick if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip || 91637737Smckusick fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { 91742466Smckusick VOP_ABORTOP(tndp); 91842466Smckusick vput(tndp->ni_dvp); 91942466Smckusick if (tndp->ni_vp) 92042466Smckusick vput(tndp->ni_vp); 92142466Smckusick VOP_ABORTOP(fndp); 92242466Smckusick vrele(fndp->ni_dvp); 92342466Smckusick vput(fndp->ni_vp); 92437737Smckusick return (EINVAL); 9259167Ssam } 92616776Smckusick ip->i_flag |= IRENAME; 9279167Ssam oldparent = dp->i_number; 9289167Ssam doingdirectory++; 9299167Ssam } 93037737Smckusick vrele(fndp->ni_dvp); 9319167Ssam 9329167Ssam /* 9339167Ssam * 1) Bump link count while we're moving stuff 9349167Ssam * around. If we crash somewhere before 9359167Ssam * completing our work, the link count 9369167Ssam * may be wrong, but correctable. 9379167Ssam */ 9389167Ssam ip->i_nlink++; 9399167Ssam ip->i_flag |= ICHG; 94037737Smckusick error = iupdat(ip, &time, &time, 1); 94116664Smckusick IUNLOCK(ip); 9429167Ssam 9439167Ssam /* 9449167Ssam * When the target exists, both the directory 94537737Smckusick * and target vnodes are returned locked. 9469167Ssam */ 94737737Smckusick dp = VTOI(tndp->ni_dvp); 94837737Smckusick xp = NULL; 94937737Smckusick if (tndp->ni_vp) 95037737Smckusick xp = VTOI(tndp->ni_vp); 9519167Ssam /* 95211641Ssam * If ".." must be changed (ie the directory gets a new 95312816Smckusick * parent) then the source directory must not be in the 95412816Smckusick * directory heirarchy above the target, as this would 95512816Smckusick * orphan everything below the source directory. Also 95612816Smckusick * the user must have write permission in the source so 95712816Smckusick * as to be able to change "..". We must repeat the call 95812816Smckusick * to namei, as the parent directory is unlocked by the 95912816Smckusick * call to checkpath(). 96011641Ssam */ 96116776Smckusick if (oldparent != dp->i_number) 96216776Smckusick newparent = dp->i_number; 96316776Smckusick if (doingdirectory && newparent) { 96441466Smckusick VOP_LOCK(fndp->ni_vp); 96541466Smckusick error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred); 96641466Smckusick VOP_UNLOCK(fndp->ni_vp); 96741466Smckusick if (error) 96812816Smckusick goto bad; 96946511Smckusick tndp->ni_nameiop &= ~(MODMASK | OPMASK); 97046511Smckusick tndp->ni_nameiop |= RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 97112816Smckusick do { 97237737Smckusick dp = VTOI(tndp->ni_dvp); 97312816Smckusick if (xp != NULL) 97438069Smckusick iput(xp); 97537737Smckusick if (error = checkpath(ip, dp, tndp->ni_cred)) 97612816Smckusick goto out; 977*47571Skarels if (error = namei(tndp, p)) 97812816Smckusick goto out; 97937737Smckusick xp = NULL; 98037737Smckusick if (tndp->ni_vp) 98137737Smckusick xp = VTOI(tndp->ni_vp); 98237737Smckusick } while (dp != VTOI(tndp->ni_dvp)); 98312816Smckusick } 98411641Ssam /* 9859167Ssam * 2) If target doesn't exist, link the target 9869167Ssam * to the source and unlink the source. 9879167Ssam * Otherwise, rewrite the target directory 9889167Ssam * entry to reference the source inode and 9899167Ssam * expunge the original entry's existence. 9909167Ssam */ 9919167Ssam if (xp == NULL) { 99237737Smckusick if (dp->i_dev != ip->i_dev) 99337737Smckusick panic("rename: EXDEV"); 9949167Ssam /* 99516776Smckusick * Account for ".." in new directory. 99616776Smckusick * When source and destination have the same 99716776Smckusick * parent we don't fool with the link count. 9989167Ssam */ 99916776Smckusick if (doingdirectory && newparent) { 100046251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 100146251Smckusick error = EMLINK; 100246251Smckusick goto bad; 100346251Smckusick } 10049167Ssam dp->i_nlink++; 10059167Ssam dp->i_flag |= ICHG; 100646251Smckusick if (error = iupdat(dp, &time, &time, 1)) 100746251Smckusick goto bad; 10089167Ssam } 100947219Smckusick if (error = direnter(ip, tndp)) { 101047219Smckusick if (doingdirectory && newparent) { 101147219Smckusick dp->i_nlink--; 101247219Smckusick dp->i_flag |= ICHG; 101347219Smckusick (void) iupdat(dp, &time, &time, 1); 101447219Smckusick } 101547219Smckusick goto bad; 101647219Smckusick } 101747234Smckusick iput(dp); 10189167Ssam } else { 101937737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 102037737Smckusick panic("rename: EXDEV"); 10219167Ssam /* 102210590Ssam * Short circuit rename(foo, foo). 102310590Ssam */ 102410590Ssam if (xp->i_number == ip->i_number) 102537737Smckusick panic("rename: same file"); 102610590Ssam /* 102724433Sbloom * If the parent directory is "sticky", then the user must 102824433Sbloom * own the parent directory, or the destination of the rename, 102924433Sbloom * otherwise the destination may not be changed (except by 103024433Sbloom * root). This implements append-only directories. 103124433Sbloom */ 103237737Smckusick if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && 103337737Smckusick tndp->ni_cred->cr_uid != dp->i_uid && 103437737Smckusick xp->i_uid != tndp->ni_cred->cr_uid) { 103524433Sbloom error = EPERM; 103624433Sbloom goto bad; 103724433Sbloom } 103824433Sbloom /* 103910051Ssam * Target must be empty if a directory 104010051Ssam * and have no links to it. 10419167Ssam * Also, insure source and target are 10429167Ssam * compatible (both directories, or both 10439167Ssam * not directories). 10449167Ssam */ 10459167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 104637737Smckusick if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 104737737Smckusick xp->i_nlink > 2) { 104810051Ssam error = ENOTEMPTY; 10499167Ssam goto bad; 10509167Ssam } 10519167Ssam if (!doingdirectory) { 105210051Ssam error = ENOTDIR; 10539167Ssam goto bad; 10549167Ssam } 105537737Smckusick cache_purge(ITOV(dp)); 10569167Ssam } else if (doingdirectory) { 105710051Ssam error = EISDIR; 10589167Ssam goto bad; 10599167Ssam } 106037737Smckusick if (error = dirrewrite(dp, ip, tndp)) 106137737Smckusick goto bad; 106245354Smckusick /* 106345354Smckusick * If the target directory is in the same 106445354Smckusick * directory as the source directory, 106545354Smckusick * decrement the link count on the parent 106645354Smckusick * of the target directory. 106745354Smckusick */ 106845354Smckusick if (doingdirectory && !newparent) { 106945354Smckusick dp->i_nlink--; 107045354Smckusick dp->i_flag |= ICHG; 107145354Smckusick } 107237737Smckusick vput(ITOV(dp)); 10739167Ssam /* 107410051Ssam * Adjust the link count of the target to 107510051Ssam * reflect the dirrewrite above. If this is 107610051Ssam * a directory it is empty and there are 107710051Ssam * no links to it, so we can squash the inode and 107810051Ssam * any space associated with it. We disallowed 107910051Ssam * renaming over top of a directory with links to 108016776Smckusick * it above, as the remaining link would point to 108116776Smckusick * a directory without "." or ".." entries. 10829167Ssam */ 108310051Ssam xp->i_nlink--; 10849167Ssam if (doingdirectory) { 108510051Ssam if (--xp->i_nlink != 0) 108610051Ssam panic("rename: linked directory"); 108739674Smckusick error = itrunc(xp, (u_long)0, IO_SYNC); 108810051Ssam } 10899167Ssam xp->i_flag |= ICHG; 109038398Smckusick iput(xp); 109110246Ssam xp = NULL; 10929167Ssam } 10939167Ssam 10949167Ssam /* 10959167Ssam * 3) Unlink the source. 10969167Ssam */ 109746511Smckusick fndp->ni_nameiop &= ~(MODMASK | OPMASK); 109846511Smckusick fndp->ni_nameiop |= DELETE | LOCKPARENT | LOCKLEAF; 1099*47571Skarels (void)namei(fndp, p); 110037737Smckusick if (fndp->ni_vp != NULL) { 110137737Smckusick xp = VTOI(fndp->ni_vp); 110237737Smckusick dp = VTOI(fndp->ni_dvp); 110337737Smckusick } else { 110446250Smckusick /* 110546250Smckusick * From name has disappeared. 110646250Smckusick */ 110746250Smckusick if (doingdirectory) 110846250Smckusick panic("rename: lost dir entry"); 110946250Smckusick vrele(ITOV(ip)); 111046250Smckusick return (0); 111137737Smckusick } 11129167Ssam /* 111337737Smckusick * Ensure that the directory entry still exists and has not 111416776Smckusick * changed while the new name has been entered. If the source is 111516776Smckusick * a file then the entry may have been unlinked or renamed. In 111616776Smckusick * either case there is no further work to be done. If the source 111716776Smckusick * is a directory then it cannot have been rmdir'ed; its link 111816776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 111937737Smckusick * The IRENAME flag ensures that it cannot be moved by another 112016776Smckusick * rename. 11219167Ssam */ 112217758Smckusick if (xp != ip) { 112316776Smckusick if (doingdirectory) 112417758Smckusick panic("rename: lost dir entry"); 112516776Smckusick } else { 11269167Ssam /* 112716776Smckusick * If the source is a directory with a 112816776Smckusick * new parent, the link count of the old 112916776Smckusick * parent directory must be decremented 113016776Smckusick * and ".." set to point to the new parent. 11319167Ssam */ 113216776Smckusick if (doingdirectory && newparent) { 11339167Ssam dp->i_nlink--; 11349167Ssam dp->i_flag |= ICHG; 113539597Smckusick error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, 113637737Smckusick sizeof (struct dirtemplate), (off_t)0, 113739597Smckusick UIO_SYSSPACE, IO_NODELOCKED, 113839597Smckusick tndp->ni_cred, (int *)0); 113916776Smckusick if (error == 0) { 114016776Smckusick if (dirbuf.dotdot_namlen != 2 || 114116776Smckusick dirbuf.dotdot_name[0] != '.' || 114216776Smckusick dirbuf.dotdot_name[1] != '.') { 114339610Smckusick dirbad(xp, 12, "rename: mangled dir"); 114416776Smckusick } else { 114516776Smckusick dirbuf.dotdot_ino = newparent; 114639597Smckusick (void) vn_rdwr(UIO_WRITE, ITOV(xp), 114716776Smckusick (caddr_t)&dirbuf, 114816776Smckusick sizeof (struct dirtemplate), 114937740Smckusick (off_t)0, UIO_SYSSPACE, 115039597Smckusick IO_NODELOCKED|IO_SYNC, 115137737Smckusick tndp->ni_cred, (int *)0); 115237737Smckusick cache_purge(ITOV(dp)); 115316776Smckusick } 115416776Smckusick } 11559167Ssam } 115637737Smckusick error = dirremove(fndp); 115737737Smckusick if (!error) { 115816776Smckusick xp->i_nlink--; 115916776Smckusick xp->i_flag |= ICHG; 11609167Ssam } 116116776Smckusick xp->i_flag &= ~IRENAME; 11629167Ssam } 11639167Ssam if (dp) 116437737Smckusick vput(ITOV(dp)); 116516776Smckusick if (xp) 116637737Smckusick vput(ITOV(xp)); 116737737Smckusick vrele(ITOV(ip)); 116837737Smckusick return (error); 11699167Ssam 11709167Ssam bad: 11719167Ssam if (xp) 117237737Smckusick vput(ITOV(xp)); 117337737Smckusick vput(ITOV(dp)); 11749167Ssam out: 11759167Ssam ip->i_nlink--; 11769167Ssam ip->i_flag |= ICHG; 117737737Smckusick vrele(ITOV(ip)); 117837737Smckusick return (error); 11797701Ssam } 11807701Ssam 11817535Sroot /* 118212756Ssam * A virgin directory (no blushing please). 118312756Ssam */ 118412756Ssam struct dirtemplate mastertemplate = { 118512756Ssam 0, 12, 1, ".", 118612756Ssam 0, DIRBLKSIZ - 12, 2, ".." 118712756Ssam }; 118812756Ssam 118912756Ssam /* 119012756Ssam * Mkdir system call 119112756Ssam */ 119237737Smckusick ufs_mkdir(ndp, vap) 119337737Smckusick struct nameidata *ndp; 119437737Smckusick struct vattr *vap; 119512756Ssam { 1196*47571Skarels struct proc *p = curproc; /* XXX */ 119712756Ssam register struct inode *ip, *dp; 119837737Smckusick struct inode *tip; 119937737Smckusick struct vnode *dvp; 120012756Ssam struct dirtemplate dirtemplate; 120137737Smckusick int error; 120237737Smckusick int dmode; 120312756Ssam 120437737Smckusick dvp = ndp->ni_dvp; 120537737Smckusick dp = VTOI(dvp); 120646251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 120746251Smckusick iput(dp); 120846251Smckusick return (EMLINK); 120946251Smckusick } 121037737Smckusick dmode = vap->va_mode&0777; 121137737Smckusick dmode |= IFDIR; 121212756Ssam /* 121312756Ssam * Must simulate part of maknode here 121412756Ssam * in order to acquire the inode, but 121512756Ssam * not have it entered in the parent 121612756Ssam * directory. The entry is made later 121712756Ssam * after writing "." and ".." entries out. 121812756Ssam */ 121941312Smckusick if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { 122012756Ssam iput(dp); 122137737Smckusick return (error); 122212756Ssam } 122337737Smckusick ip = tip; 122441312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 122541312Smckusick ip->i_gid = dp->i_gid; 122612756Ssam #ifdef QUOTA 122741312Smckusick if ((error = getinoquota(ip)) || 122841312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 122941312Smckusick ifree(ip, ip->i_number, dmode); 123041312Smckusick iput(ip); 123141312Smckusick iput(dp); 123241312Smckusick return (error); 123341312Smckusick } 123412756Ssam #endif 123512756Ssam ip->i_flag |= IACC|IUPD|ICHG; 123637737Smckusick ip->i_mode = dmode; 123737737Smckusick ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ 123812756Ssam ip->i_nlink = 2; 123937737Smckusick error = iupdat(ip, &time, &time, 1); 124012756Ssam 124112756Ssam /* 124212756Ssam * Bump link count in parent directory 124312756Ssam * to reflect work done below. Should 124412756Ssam * be done before reference is created 124512756Ssam * so reparation is possible if we crash. 124612756Ssam */ 124712756Ssam dp->i_nlink++; 124812756Ssam dp->i_flag |= ICHG; 124947219Smckusick if (error = iupdat(dp, &time, &time, 1)) 125047219Smckusick goto bad; 125112756Ssam 125212756Ssam /* 125312756Ssam * Initialize directory with "." 125412756Ssam * and ".." from static template. 125512756Ssam */ 125612756Ssam dirtemplate = mastertemplate; 125712756Ssam dirtemplate.dot_ino = ip->i_number; 125812756Ssam dirtemplate.dotdot_ino = dp->i_number; 125939597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, 126037737Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 126139597Smckusick IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0); 126237737Smckusick if (error) { 126312756Ssam dp->i_nlink--; 126412756Ssam dp->i_flag |= ICHG; 126512756Ssam goto bad; 126612756Ssam } 126743288Smckusick if (DIRBLKSIZ > dp->i_fs->fs_fsize) { 126837737Smckusick panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ 126943288Smckusick } else { 127018103Smckusick ip->i_size = DIRBLKSIZ; 127143288Smckusick ip->i_flag |= ICHG; 127243288Smckusick } 127312756Ssam /* 127412756Ssam * Directory all set up, now 127512756Ssam * install the entry for it in 127612756Ssam * the parent directory. 127712756Ssam */ 127847219Smckusick if (error = direnter(ip, ndp)) { 127946511Smckusick ndp->ni_nameiop &= ~(MODMASK | OPMASK); 128047219Smckusick ndp->ni_nameiop |= LOOKUP | LOCKLEAF | NOCACHE; 1281*47571Skarels error = namei(ndp, p); 128237737Smckusick if (!error) { 128347219Smckusick iput(dp); 128437737Smckusick dp = VTOI(ndp->ni_vp); 128512756Ssam dp->i_nlink--; 128612756Ssam dp->i_flag |= ICHG; 128712756Ssam } 128812756Ssam } 128912756Ssam bad: 129012756Ssam /* 129112756Ssam * No need to do an explicit itrunc here, 129237737Smckusick * vrele will do this for us because we set 129312756Ssam * the link count to 0. 129412756Ssam */ 129537737Smckusick if (error) { 129612756Ssam ip->i_nlink = 0; 129712756Ssam ip->i_flag |= ICHG; 129838144Smckusick iput(ip); 129938144Smckusick } else 130038144Smckusick ndp->ni_vp = ITOV(ip); 130147219Smckusick iput(dp); 130237737Smckusick return (error); 130312756Ssam } 130412756Ssam 130512756Ssam /* 130612756Ssam * Rmdir system call. 130712756Ssam */ 130837737Smckusick ufs_rmdir(ndp) 130937737Smckusick register struct nameidata *ndp; 131012756Ssam { 131112756Ssam register struct inode *ip, *dp; 131237737Smckusick int error = 0; 131312756Ssam 131437737Smckusick ip = VTOI(ndp->ni_vp); 131537737Smckusick dp = VTOI(ndp->ni_dvp); 131612756Ssam /* 131712756Ssam * No rmdir "." please. 131812756Ssam */ 131912756Ssam if (dp == ip) { 132037737Smckusick vrele(ITOV(dp)); 132112756Ssam iput(ip); 132237737Smckusick return (EINVAL); 132312756Ssam } 132412756Ssam /* 132512756Ssam * Verify the directory is empty (and valid). 132612756Ssam * (Rmdir ".." won't be valid since 132712756Ssam * ".." will contain a reference to 132812756Ssam * the current directory and thus be 132912756Ssam * non-empty.) 133012756Ssam */ 133137737Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { 133237737Smckusick error = ENOTEMPTY; 133312756Ssam goto out; 133412756Ssam } 133512756Ssam /* 133612756Ssam * Delete reference to directory before purging 133712756Ssam * inode. If we crash in between, the directory 133812756Ssam * will be reattached to lost+found, 133912756Ssam */ 134037737Smckusick if (error = dirremove(ndp)) 134112756Ssam goto out; 134212756Ssam dp->i_nlink--; 134312756Ssam dp->i_flag |= ICHG; 134437737Smckusick cache_purge(ITOV(dp)); 134512756Ssam iput(dp); 134637737Smckusick ndp->ni_dvp = NULL; 134712756Ssam /* 134812756Ssam * Truncate inode. The only stuff left 134912756Ssam * in the directory is "." and "..". The 135012756Ssam * "." reference is inconsequential since 135112756Ssam * we're quashing it. The ".." reference 135212756Ssam * has already been adjusted above. We've 135312756Ssam * removed the "." reference and the reference 135412756Ssam * in the parent directory, but there may be 135512756Ssam * other hard links so decrement by 2 and 135612756Ssam * worry about them later. 135712756Ssam */ 135812756Ssam ip->i_nlink -= 2; 135939674Smckusick error = itrunc(ip, (u_long)0, IO_SYNC); 136037737Smckusick cache_purge(ITOV(ip)); 136112756Ssam out: 136237737Smckusick if (ndp->ni_dvp) 136312756Ssam iput(dp); 136412756Ssam iput(ip); 136537737Smckusick return (error); 136612756Ssam } 136712756Ssam 136837737Smckusick /* 136937737Smckusick * symlink -- make a symbolic link 137037737Smckusick */ 137137737Smckusick ufs_symlink(ndp, vap, target) 137237737Smckusick struct nameidata *ndp; 137337737Smckusick struct vattr *vap; 137437737Smckusick char *target; 137512756Ssam { 137637737Smckusick struct inode *ip; 137737737Smckusick int error; 137812756Ssam 137937737Smckusick error = maknode(IFLNK | vap->va_mode, ndp, &ip); 138037737Smckusick if (error) 138137737Smckusick return (error); 138239597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, 138339597Smckusick UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0); 138437737Smckusick iput(ip); 138537737Smckusick return (error); 138637737Smckusick } 138737737Smckusick 138837737Smckusick /* 138937737Smckusick * Vnode op for read and write 139037737Smckusick */ 139140345Smckusick ufs_readdir(vp, uio, cred, eofflagp) 139237737Smckusick struct vnode *vp; 139337737Smckusick register struct uio *uio; 139437737Smckusick struct ucred *cred; 139540345Smckusick int *eofflagp; 139637737Smckusick { 139739597Smckusick int count, lost, error; 139837737Smckusick 139937737Smckusick count = uio->uio_resid; 140037737Smckusick count &= ~(DIRBLKSIZ - 1); 140139597Smckusick lost = uio->uio_resid - count; 140239597Smckusick if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) 140337737Smckusick return (EINVAL); 140437737Smckusick uio->uio_resid = count; 140537737Smckusick uio->uio_iov->iov_len = count; 140639597Smckusick error = ufs_read(vp, uio, 0, cred); 140739597Smckusick uio->uio_resid += lost; 140840345Smckusick if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) 140940345Smckusick *eofflagp = 1; 141040345Smckusick else 141140345Smckusick *eofflagp = 0; 141237737Smckusick return (error); 141337737Smckusick } 141437737Smckusick 141537737Smckusick /* 141637737Smckusick * Return target name of a symbolic link 141737737Smckusick */ 141837737Smckusick ufs_readlink(vp, uiop, cred) 141937737Smckusick struct vnode *vp; 142037737Smckusick struct uio *uiop; 142137737Smckusick struct ucred *cred; 142237737Smckusick { 142337737Smckusick 142439597Smckusick return (ufs_read(vp, uiop, 0, cred)); 142537737Smckusick } 142637737Smckusick 142737737Smckusick /* 142837737Smckusick * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 142942466Smckusick * done. Nothing to do at the moment. 143037737Smckusick */ 143142466Smckusick /* ARGSUSED */ 143237737Smckusick ufs_abortop(ndp) 143342466Smckusick struct nameidata *ndp; 143437737Smckusick { 143537737Smckusick 143642466Smckusick return (0); 143712756Ssam } 143812756Ssam 143939909Smckusick /* 144039909Smckusick * Lock an inode. 144139909Smckusick */ 144237737Smckusick ufs_lock(vp) 144337737Smckusick struct vnode *vp; 144437737Smckusick { 144537737Smckusick register struct inode *ip = VTOI(vp); 144637737Smckusick 144737737Smckusick ILOCK(ip); 144837737Smckusick return (0); 144937737Smckusick } 145037737Smckusick 145139909Smckusick /* 145239909Smckusick * Unlock an inode. 145339909Smckusick */ 145437737Smckusick ufs_unlock(vp) 145537737Smckusick struct vnode *vp; 145637737Smckusick { 145737737Smckusick register struct inode *ip = VTOI(vp); 145837737Smckusick 145937737Smckusick if (!(ip->i_flag & ILOCKED)) 146037737Smckusick panic("ufs_unlock NOT LOCKED"); 146137737Smckusick IUNLOCK(ip); 146237737Smckusick return (0); 146337737Smckusick } 146437737Smckusick 146512756Ssam /* 146639909Smckusick * Check for a locked inode. 146739909Smckusick */ 146839909Smckusick ufs_islocked(vp) 146939909Smckusick struct vnode *vp; 147039909Smckusick { 147139909Smckusick 147239909Smckusick if (VTOI(vp)->i_flag & ILOCKED) 147339909Smckusick return (1); 147439909Smckusick return (0); 147539909Smckusick } 147639909Smckusick 147739909Smckusick /* 147837737Smckusick * Get access to bmap 147912756Ssam */ 148037737Smckusick ufs_bmap(vp, bn, vpp, bnp) 148137737Smckusick struct vnode *vp; 148237737Smckusick daddr_t bn; 148337737Smckusick struct vnode **vpp; 148437737Smckusick daddr_t *bnp; 148512756Ssam { 148637737Smckusick struct inode *ip = VTOI(vp); 148712756Ssam 148837737Smckusick if (vpp != NULL) 148937737Smckusick *vpp = ip->i_devvp; 149037737Smckusick if (bnp == NULL) 149137737Smckusick return (0); 149241538Smckusick return (bmap(ip, bn, bnp)); 149312756Ssam } 149437737Smckusick 149537737Smckusick /* 149641538Smckusick * Calculate the logical to physical mapping if not done already, 149741538Smckusick * then call the device strategy routine. 149837737Smckusick */ 149941538Smckusick int checkoverlap = 0; 150039674Smckusick 150137737Smckusick ufs_strategy(bp) 150237737Smckusick register struct buf *bp; 150337737Smckusick { 150439674Smckusick register struct inode *ip = VTOI(bp->b_vp); 150539674Smckusick struct vnode *vp; 150639674Smckusick int error; 150739674Smckusick 150839674Smckusick if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 150939674Smckusick panic("ufs_strategy: spec"); 151039674Smckusick if (bp->b_blkno == bp->b_lblkno) { 151139674Smckusick if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno)) 151239674Smckusick return (error); 151339896Smckusick if ((long)bp->b_blkno == -1) 151439674Smckusick clrbuf(bp); 151539674Smckusick } 151639896Smckusick if ((long)bp->b_blkno == -1) { 151739896Smckusick biodone(bp); 151839674Smckusick return (0); 151939896Smckusick } 152041538Smckusick #ifdef DIAGNOSTIC 152139674Smckusick if (checkoverlap) { 152241538Smckusick register struct buf *ep; 152341538Smckusick struct buf *ebp; 152441538Smckusick daddr_t start, last; 152541538Smckusick 152639674Smckusick ebp = &buf[nbuf]; 152739674Smckusick start = bp->b_blkno; 152839674Smckusick last = start + btodb(bp->b_bcount) - 1; 152939674Smckusick for (ep = buf; ep < ebp; ep++) { 153039674Smckusick if (ep == bp || (ep->b_flags & B_INVAL) || 153141396Smckusick ep->b_vp == NULLVP) 153239674Smckusick continue; 153339674Smckusick if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0)) 153439674Smckusick continue; 153539674Smckusick if (vp != ip->i_devvp) 153639674Smckusick continue; 153739674Smckusick /* look for overlap */ 153839674Smckusick if (ep->b_bcount == 0 || ep->b_blkno > last || 153939674Smckusick ep->b_blkno + btodb(ep->b_bcount) <= start) 154039674Smckusick continue; 154139896Smckusick vprint("Disk overlap", vp); 154239896Smckusick printf("\tstart %d, end %d overlap start %d, end %d\n", 154339896Smckusick start, last, ep->b_blkno, 154439896Smckusick ep->b_blkno + btodb(ep->b_bcount) - 1); 154541538Smckusick panic("Disk buffer overlap"); 154639674Smckusick } 154739674Smckusick } 154841538Smckusick #endif /* DIAGNOSTIC */ 154939674Smckusick vp = ip->i_devvp; 155039674Smckusick bp->b_dev = vp->v_rdev; 155139674Smckusick (*(vp->v_op->vn_strategy))(bp); 155237737Smckusick return (0); 155337737Smckusick } 155437737Smckusick 155537737Smckusick /* 155639674Smckusick * Print out the contents of an inode. 155739674Smckusick */ 155839674Smckusick ufs_print(vp) 155939674Smckusick struct vnode *vp; 156039674Smckusick { 156139674Smckusick register struct inode *ip = VTOI(vp); 156239674Smckusick 156340293Smckusick printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number, 156440293Smckusick major(ip->i_dev), minor(ip->i_dev)); 156540293Smckusick #ifdef FIFO 156640293Smckusick if (vp->v_type == VFIFO) 156740293Smckusick fifo_printinfo(vp); 156840293Smckusick #endif /* FIFO */ 156940293Smckusick printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : ""); 157039900Smckusick if (ip->i_spare0 == 0) 157139900Smckusick return; 157239900Smckusick printf("\towner pid %d", ip->i_spare0); 157339900Smckusick if (ip->i_spare1) 157439900Smckusick printf(" waiting pid %d", ip->i_spare1); 157539900Smckusick printf("\n"); 157639674Smckusick } 157739674Smckusick 157839674Smckusick /* 157939628Smckusick * Read wrapper for special devices. 158039628Smckusick */ 158139628Smckusick ufsspec_read(vp, uio, ioflag, cred) 158239628Smckusick struct vnode *vp; 158339628Smckusick struct uio *uio; 158439628Smckusick int ioflag; 158539628Smckusick struct ucred *cred; 158639628Smckusick { 158739628Smckusick 158839628Smckusick /* 158939628Smckusick * Set access flag. 159039628Smckusick */ 159139628Smckusick VTOI(vp)->i_flag |= IACC; 159239628Smckusick return (spec_read(vp, uio, ioflag, cred)); 159339628Smckusick } 159439628Smckusick 159539628Smckusick /* 159639628Smckusick * Write wrapper for special devices. 159739628Smckusick */ 159839628Smckusick ufsspec_write(vp, uio, ioflag, cred) 159939628Smckusick struct vnode *vp; 160039628Smckusick struct uio *uio; 160139628Smckusick int ioflag; 160239628Smckusick struct ucred *cred; 160339628Smckusick { 160439628Smckusick 160539628Smckusick /* 160639628Smckusick * Set update and change flags. 160739628Smckusick */ 160839628Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 160939628Smckusick return (spec_write(vp, uio, ioflag, cred)); 161039628Smckusick } 161139628Smckusick 161239628Smckusick /* 161339628Smckusick * Close wrapper for special devices. 161439628Smckusick * 161539628Smckusick * Update the times on the inode then do device close. 161639628Smckusick */ 161739628Smckusick ufsspec_close(vp, fflag, cred) 161839628Smckusick struct vnode *vp; 161939628Smckusick int fflag; 162039628Smckusick struct ucred *cred; 162139628Smckusick { 162239628Smckusick register struct inode *ip = VTOI(vp); 162339628Smckusick 162439815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 162539628Smckusick ITIMES(ip, &time, &time); 162639628Smckusick return (spec_close(vp, fflag, cred)); 162739628Smckusick } 162839628Smckusick 162940290Smckusick #ifdef FIFO 163039628Smckusick /* 163140290Smckusick * Read wrapper for fifo's 163240290Smckusick */ 163340290Smckusick ufsfifo_read(vp, uio, ioflag, cred) 163440290Smckusick struct vnode *vp; 163540290Smckusick struct uio *uio; 163640290Smckusick int ioflag; 163740290Smckusick struct ucred *cred; 163840290Smckusick { 163940290Smckusick 164040290Smckusick /* 164140290Smckusick * Set access flag. 164240290Smckusick */ 164340290Smckusick VTOI(vp)->i_flag |= IACC; 164440290Smckusick return (fifo_read(vp, uio, ioflag, cred)); 164540290Smckusick } 164640290Smckusick 164740290Smckusick /* 164840290Smckusick * Write wrapper for fifo's. 164940290Smckusick */ 165040290Smckusick ufsfifo_write(vp, uio, ioflag, cred) 165140290Smckusick struct vnode *vp; 165240290Smckusick struct uio *uio; 165340290Smckusick int ioflag; 165440290Smckusick struct ucred *cred; 165540290Smckusick { 165640290Smckusick 165740290Smckusick /* 165840290Smckusick * Set update and change flags. 165940290Smckusick */ 166040290Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 166140290Smckusick return (fifo_write(vp, uio, ioflag, cred)); 166240290Smckusick } 166340290Smckusick 166440290Smckusick /* 166540290Smckusick * Close wrapper for fifo's. 166640290Smckusick * 166740290Smckusick * Update the times on the inode then do device close. 166840290Smckusick */ 166940290Smckusick ufsfifo_close(vp, fflag, cred) 167040290Smckusick struct vnode *vp; 167140290Smckusick int fflag; 167240290Smckusick struct ucred *cred; 167340290Smckusick { 167440290Smckusick register struct inode *ip = VTOI(vp); 167540290Smckusick 167640290Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 167740290Smckusick ITIMES(ip, &time, &time); 167840290Smckusick return (fifo_close(vp, fflag, cred)); 167940290Smckusick } 168040290Smckusick #endif /* FIFO */ 168140290Smckusick 168240290Smckusick /* 168337737Smckusick * Make a new file. 168437737Smckusick */ 168537737Smckusick maknode(mode, ndp, ipp) 168637737Smckusick int mode; 168737737Smckusick register struct nameidata *ndp; 168837737Smckusick struct inode **ipp; 168937737Smckusick { 169037737Smckusick register struct inode *ip; 169137737Smckusick struct inode *tip; 169237737Smckusick register struct inode *pdir = VTOI(ndp->ni_dvp); 169337737Smckusick ino_t ipref; 169437737Smckusick int error; 169537737Smckusick 169637737Smckusick *ipp = 0; 169741312Smckusick if ((mode & IFMT) == 0) 169841312Smckusick mode |= IFREG; 169937737Smckusick if ((mode & IFMT) == IFDIR) 170037737Smckusick ipref = dirpref(pdir->i_fs); 170137737Smckusick else 170237737Smckusick ipref = pdir->i_number; 170341312Smckusick if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { 170437737Smckusick iput(pdir); 170537737Smckusick return (error); 170637737Smckusick } 170737737Smckusick ip = tip; 170841312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 170941312Smckusick ip->i_gid = pdir->i_gid; 171037737Smckusick #ifdef QUOTA 171141312Smckusick if ((error = getinoquota(ip)) || 171241312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 171341312Smckusick ifree(ip, ip->i_number, mode); 171441312Smckusick iput(ip); 171541312Smckusick iput(pdir); 171641312Smckusick return (error); 171741312Smckusick } 171837737Smckusick #endif 171937737Smckusick ip->i_flag |= IACC|IUPD|ICHG; 172037737Smckusick ip->i_mode = mode; 172137737Smckusick ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ 172237737Smckusick ip->i_nlink = 1; 172337737Smckusick if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && 172437737Smckusick suser(ndp->ni_cred, NULL)) 172537737Smckusick ip->i_mode &= ~ISGID; 172637737Smckusick 172737737Smckusick /* 172837737Smckusick * Make sure inode goes to disk before directory entry. 172937737Smckusick */ 173041312Smckusick if (error = iupdat(ip, &time, &time, 1)) 173141312Smckusick goto bad; 173247219Smckusick if (error = direnter(ip, ndp)) 173341312Smckusick goto bad; 173447219Smckusick iput(pdir); 173537737Smckusick *ipp = ip; 173637737Smckusick return (0); 173741312Smckusick 173841312Smckusick bad: 173941312Smckusick /* 174041312Smckusick * Write error occurred trying to update the inode 174141312Smckusick * or the directory so must deallocate the inode. 174241312Smckusick */ 174347219Smckusick iput(pdir); 174441312Smckusick ip->i_nlink = 0; 174541312Smckusick ip->i_flag |= ICHG; 174641312Smckusick iput(ip); 174741312Smckusick return (error); 174837737Smckusick } 174946207Smckusick 175046207Smckusick /* 175146207Smckusick * Advisory record locking support 175246207Smckusick */ 175346207Smckusick ufs_advlock(vp, id, op, fl, flags) 175446207Smckusick struct vnode *vp; 175546207Smckusick caddr_t id; 175646207Smckusick int op; 175746207Smckusick register struct flock *fl; 175846207Smckusick int flags; 175946207Smckusick { 176046207Smckusick register struct inode *ip = VTOI(vp); 176146207Smckusick register struct lockf *lock; 176246207Smckusick off_t start, end; 176346207Smckusick int error; 176446207Smckusick 176546207Smckusick /* 176646207Smckusick * Avoid the common case of unlocking when inode has no locks. 176746207Smckusick */ 176846207Smckusick if (ip->i_lockf == (struct lockf *)0) { 176946207Smckusick if (op != F_SETLK) { 177046207Smckusick fl->l_type = F_UNLCK; 177146207Smckusick return (0); 177246207Smckusick } 177346207Smckusick } 177446207Smckusick /* 177546207Smckusick * Convert the flock structure into a start and end. 177646207Smckusick */ 177746207Smckusick switch (fl->l_whence) { 177846207Smckusick 177946207Smckusick case SEEK_SET: 178046207Smckusick case SEEK_CUR: 178146207Smckusick /* 178246207Smckusick * Caller is responsible for adding any necessary offset 178346207Smckusick * when SEEK_CUR is used. 178446207Smckusick */ 178546207Smckusick start = fl->l_start; 178646207Smckusick break; 178746207Smckusick 178846207Smckusick case SEEK_END: 178946207Smckusick start = ip->i_size + fl->l_start; 179046207Smckusick break; 179146207Smckusick 179246207Smckusick default: 179346207Smckusick return (EINVAL); 179446207Smckusick } 179546207Smckusick if (start < 0) 179646207Smckusick return (EINVAL); 179746207Smckusick if (fl->l_len == 0) 179846207Smckusick end = -1; 179946207Smckusick else 180046507Smckusick end = start + fl->l_len - 1; 180146207Smckusick /* 180246207Smckusick * Create the lockf structure 180346207Smckusick */ 180446207Smckusick MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); 180546207Smckusick lock->lf_start = start; 180646207Smckusick lock->lf_end = end; 180746207Smckusick lock->lf_id = id; 180846207Smckusick lock->lf_inode = ip; 180946207Smckusick lock->lf_type = fl->l_type; 181046207Smckusick lock->lf_next = (struct lockf *)0; 181146207Smckusick lock->lf_block = (struct lockf *)0; 181246207Smckusick lock->lf_flags = flags; 181346207Smckusick /* 181446207Smckusick * Do the requested operation. 181546207Smckusick */ 181646207Smckusick switch(op) { 181746207Smckusick case F_SETLK: 181846679Smckusick return (lf_setlock(lock)); 181946207Smckusick 182046207Smckusick case F_UNLCK: 182146679Smckusick error = lf_clearlock(lock); 182246679Smckusick FREE(lock, M_LOCKF); 182346679Smckusick return (error); 182446207Smckusick 182546207Smckusick case F_GETLK: 182646679Smckusick error = lf_getlock(lock, fl); 182746679Smckusick FREE(lock, M_LOCKF); 182846679Smckusick return (error); 182946207Smckusick 183046207Smckusick default: 183146207Smckusick free(lock, M_LOCKF); 183246207Smckusick return (EINVAL); 183346207Smckusick } 183446207Smckusick /* NOTREACHED */ 183546207Smckusick } 1836