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*47219Smckusick * @(#)lfs_vnops.c 7.56 (Berkeley) 03/11/91 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" 2446207Smckusick #include "fcntl.h" 2546207Smckusick #include "malloc.h" 2646207Smckusick #include "../ufs/lockf.h" 2741312Smckusick #include "../ufs/quota.h" 2837737Smckusick #include "../ufs/inode.h" 2937737Smckusick #include "../ufs/fs.h" 3037Sbill 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(), 11539435Smckusick spec_badop(), 11646679Smckusick nullop(); 11739435Smckusick 11839435Smckusick struct vnodeops spec_inodeops = { 11939597Smckusick spec_lookup, /* lookup */ 12039597Smckusick spec_badop, /* create */ 12139597Smckusick spec_badop, /* mknod */ 12239597Smckusick spec_open, /* open */ 12339628Smckusick ufsspec_close, /* close */ 12439597Smckusick ufs_access, /* access */ 12539597Smckusick ufs_getattr, /* getattr */ 12639597Smckusick ufs_setattr, /* setattr */ 12739628Smckusick ufsspec_read, /* read */ 12839628Smckusick ufsspec_write, /* write */ 12939597Smckusick spec_ioctl, /* ioctl */ 13039597Smckusick spec_select, /* select */ 13139597Smckusick spec_badop, /* mmap */ 13246679Smckusick nullop, /* fsync */ 13339597Smckusick spec_badop, /* seek */ 13439597Smckusick spec_badop, /* remove */ 13539597Smckusick spec_badop, /* link */ 13639597Smckusick spec_badop, /* rename */ 13739597Smckusick spec_badop, /* mkdir */ 13839597Smckusick spec_badop, /* rmdir */ 13939597Smckusick spec_badop, /* symlink */ 14039597Smckusick spec_badop, /* readdir */ 14139597Smckusick spec_badop, /* readlink */ 14239597Smckusick spec_badop, /* abortop */ 14339597Smckusick ufs_inactive, /* inactive */ 14439597Smckusick ufs_reclaim, /* reclaim */ 14539597Smckusick ufs_lock, /* lock */ 14639597Smckusick ufs_unlock, /* unlock */ 14739674Smckusick spec_bmap, /* bmap */ 14839597Smckusick spec_strategy, /* strategy */ 14939674Smckusick ufs_print, /* print */ 15039909Smckusick ufs_islocked, /* islocked */ 15146207Smckusick spec_advlock, /* advlock */ 15239435Smckusick }; 15339435Smckusick 15440290Smckusick #ifdef FIFO 15540290Smckusick int fifo_lookup(), 15640290Smckusick fifo_open(), 15740290Smckusick ufsfifo_read(), 15840290Smckusick ufsfifo_write(), 15940290Smckusick fifo_bmap(), 16040290Smckusick fifo_ioctl(), 16140290Smckusick fifo_select(), 16240290Smckusick ufsfifo_close(), 16340290Smckusick fifo_print(), 16446207Smckusick fifo_advlock(), 16546679Smckusick fifo_badop(); 16640290Smckusick 16740290Smckusick struct vnodeops fifo_inodeops = { 16840290Smckusick fifo_lookup, /* lookup */ 16940290Smckusick fifo_badop, /* create */ 17040290Smckusick fifo_badop, /* mknod */ 17140290Smckusick fifo_open, /* open */ 17240290Smckusick ufsfifo_close, /* close */ 17340290Smckusick ufs_access, /* access */ 17440290Smckusick ufs_getattr, /* getattr */ 17540290Smckusick ufs_setattr, /* setattr */ 17640290Smckusick ufsfifo_read, /* read */ 17740290Smckusick ufsfifo_write, /* write */ 17840290Smckusick fifo_ioctl, /* ioctl */ 17940290Smckusick fifo_select, /* select */ 18040290Smckusick fifo_badop, /* mmap */ 18146679Smckusick nullop, /* fsync */ 18240290Smckusick fifo_badop, /* seek */ 18340290Smckusick fifo_badop, /* remove */ 18440290Smckusick fifo_badop, /* link */ 18540290Smckusick fifo_badop, /* rename */ 18640290Smckusick fifo_badop, /* mkdir */ 18740290Smckusick fifo_badop, /* rmdir */ 18840290Smckusick fifo_badop, /* symlink */ 18940290Smckusick fifo_badop, /* readdir */ 19040290Smckusick fifo_badop, /* readlink */ 19140290Smckusick fifo_badop, /* abortop */ 19240290Smckusick ufs_inactive, /* inactive */ 19340290Smckusick ufs_reclaim, /* reclaim */ 19440290Smckusick ufs_lock, /* lock */ 19540290Smckusick ufs_unlock, /* unlock */ 19640290Smckusick fifo_bmap, /* bmap */ 19740290Smckusick fifo_badop, /* strategy */ 19840290Smckusick ufs_print, /* print */ 19940290Smckusick ufs_islocked, /* islocked */ 20046207Smckusick fifo_advlock, /* advlock */ 20137737Smckusick }; 20240290Smckusick #endif /* FIFO */ 20340290Smckusick 20440290Smckusick enum vtype iftovt_tab[16] = { 20540290Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 20640290Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 20737737Smckusick }; 20840290Smckusick int vttoif_tab[9] = { 20940290Smckusick 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT, 21040290Smckusick }; 2116254Sroot 2129167Ssam /* 21337737Smckusick * Create a regular file 2149167Ssam */ 21537737Smckusick ufs_create(ndp, vap) 21637737Smckusick struct nameidata *ndp; 21737737Smckusick struct vattr *vap; 2186254Sroot { 21937737Smckusick struct inode *ip; 22037737Smckusick int error; 2216254Sroot 22237737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 22337737Smckusick return (error); 22437737Smckusick ndp->ni_vp = ITOV(ip); 22537737Smckusick return (0); 2266254Sroot } 2276254Sroot 22837Sbill /* 22937737Smckusick * Mknod vnode call 2306254Sroot */ 23137737Smckusick /* ARGSUSED */ 23237737Smckusick ufs_mknod(ndp, vap, cred) 23337737Smckusick struct nameidata *ndp; 23437737Smckusick struct ucred *cred; 23537737Smckusick struct vattr *vap; 2366254Sroot { 23739435Smckusick register struct vnode *vp; 23837737Smckusick struct inode *ip; 23937737Smckusick int error; 2406254Sroot 24137737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 24237737Smckusick return (error); 24340290Smckusick ip->i_flag |= IACC|IUPD|ICHG; 24440290Smckusick if (vap->va_rdev != VNOVAL) { 24537737Smckusick /* 24637737Smckusick * Want to be able to use this to make badblock 24737737Smckusick * inodes, so don't truncate the dev number. 24837737Smckusick */ 24939608Smckusick ip->i_rdev = vap->va_rdev; 25012756Ssam } 25137737Smckusick /* 25237737Smckusick * Remove inode so that it will be reloaded by iget and 25337737Smckusick * checked to see if it is an alias of an existing entry 25437737Smckusick * in the inode cache. 25537737Smckusick */ 25640290Smckusick vp = ITOV(ip); 25740290Smckusick vput(vp); 25839435Smckusick vp->v_type = VNON; 25939435Smckusick vgone(vp); 26037737Smckusick return (0); 2616254Sroot } 2626254Sroot 2636254Sroot /* 26437737Smckusick * Open called. 26537737Smckusick * 26637737Smckusick * Nothing to do. 2676254Sroot */ 26837737Smckusick /* ARGSUSED */ 26937737Smckusick ufs_open(vp, mode, cred) 27037737Smckusick struct vnode *vp; 27137737Smckusick int mode; 27237737Smckusick struct ucred *cred; 2736254Sroot { 2746254Sroot 27537737Smckusick return (0); 2766254Sroot } 2776254Sroot 2786254Sroot /* 27937737Smckusick * Close called 28037737Smckusick * 28137737Smckusick * Update the times on the inode. 2826254Sroot */ 28337737Smckusick /* ARGSUSED */ 28437737Smckusick ufs_close(vp, fflag, cred) 28537737Smckusick struct vnode *vp; 28637737Smckusick int fflag; 28737737Smckusick struct ucred *cred; 2886254Sroot { 28937737Smckusick register struct inode *ip = VTOI(vp); 2906254Sroot 29139815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 29237737Smckusick ITIMES(ip, &time, &time); 29337737Smckusick return (0); 2946254Sroot } 2956254Sroot 29641312Smckusick /* 29741312Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 29841312Smckusick * The mode is shifted to select the owner/group/other fields. The 29941312Smckusick * super user is granted all permissions. 30041312Smckusick */ 30137737Smckusick ufs_access(vp, mode, cred) 30237737Smckusick struct vnode *vp; 30341312Smckusick register int mode; 30437737Smckusick struct ucred *cred; 3056254Sroot { 30641312Smckusick register struct inode *ip = VTOI(vp); 30741312Smckusick register gid_t *gp; 30841312Smckusick int i, error; 3096254Sroot 31041312Smckusick #ifdef DIAGNOSTIC 31141312Smckusick if (!VOP_ISLOCKED(vp)) { 31241312Smckusick vprint("ufs_access: not locked", vp); 31341312Smckusick panic("ufs_access: not locked"); 31441312Smckusick } 31541312Smckusick #endif 31641312Smckusick #ifdef QUOTA 31741312Smckusick if (mode & VWRITE) { 31841312Smckusick switch (vp->v_type) { 31941312Smckusick case VREG: case VDIR: case VLNK: 32041312Smckusick if (error = getinoquota(ip)) 32141312Smckusick return (error); 32241312Smckusick } 32341312Smckusick } 32441312Smckusick #endif /* QUOTA */ 32541312Smckusick /* 32641312Smckusick * If you're the super-user, you always get access. 32741312Smckusick */ 32841312Smckusick if (cred->cr_uid == 0) 32941312Smckusick return (0); 33041312Smckusick /* 33141312Smckusick * Access check is based on only one of owner, group, public. 33241312Smckusick * If not owner, then check group. If not a member of the 33341312Smckusick * group, then check public access. 33441312Smckusick */ 33541312Smckusick if (cred->cr_uid != ip->i_uid) { 33641312Smckusick mode >>= 3; 33741312Smckusick gp = cred->cr_groups; 33841312Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 33941312Smckusick if (ip->i_gid == *gp) 34041312Smckusick goto found; 34141312Smckusick mode >>= 3; 34241312Smckusick found: 34341312Smckusick ; 34441312Smckusick } 34541312Smckusick if ((ip->i_mode & mode) != 0) 34641312Smckusick return (0); 34741312Smckusick return (EACCES); 3486254Sroot } 3496254Sroot 35037737Smckusick /* ARGSUSED */ 35137737Smckusick ufs_getattr(vp, vap, cred) 35237737Smckusick struct vnode *vp; 35337737Smckusick register struct vattr *vap; 35437737Smckusick struct ucred *cred; 3556254Sroot { 35637737Smckusick register struct inode *ip = VTOI(vp); 3576254Sroot 35837737Smckusick ITIMES(ip, &time, &time); 3596254Sroot /* 36037737Smckusick * Copy from inode table 3616254Sroot */ 36237737Smckusick vap->va_fsid = ip->i_dev; 36337737Smckusick vap->va_fileid = ip->i_number; 36437737Smckusick vap->va_mode = ip->i_mode & ~IFMT; 36537737Smckusick vap->va_nlink = ip->i_nlink; 36637737Smckusick vap->va_uid = ip->i_uid; 36737737Smckusick vap->va_gid = ip->i_gid; 36837737Smckusick vap->va_rdev = (dev_t)ip->i_rdev; 36941312Smckusick #ifdef tahoe 37041312Smckusick vap->va_size = ip->i_size; 37141312Smckusick vap->va_size_rsv = 0; 37241312Smckusick #else 37340641Smckusick vap->va_qsize = ip->i_din.di_qsize; 37441312Smckusick #endif 37537737Smckusick vap->va_atime.tv_sec = ip->i_atime; 37638578Smckusick vap->va_atime.tv_usec = 0; 37737737Smckusick vap->va_mtime.tv_sec = ip->i_mtime; 37838578Smckusick vap->va_mtime.tv_usec = 0; 37937737Smckusick vap->va_ctime.tv_sec = ip->i_ctime; 38038578Smckusick vap->va_ctime.tv_usec = 0; 38138254Smckusick vap->va_flags = ip->i_flags; 38238254Smckusick vap->va_gen = ip->i_gen; 38337737Smckusick /* this doesn't belong here */ 38437737Smckusick if (vp->v_type == VBLK) 38537737Smckusick vap->va_blocksize = BLKDEV_IOSIZE; 38637737Smckusick else if (vp->v_type == VCHR) 38737737Smckusick vap->va_blocksize = MAXBSIZE; 3887142Smckusick else 38937737Smckusick vap->va_blocksize = ip->i_fs->fs_bsize; 39038657Smckusick vap->va_bytes = dbtob(ip->i_blocks); 39140641Smckusick vap->va_bytes_rsv = 0; 39237737Smckusick vap->va_type = vp->v_type; 39337737Smckusick return (0); 3946254Sroot } 3956254Sroot 3966254Sroot /* 39737737Smckusick * Set attribute vnode op. called from several syscalls 3986254Sroot */ 39937737Smckusick ufs_setattr(vp, vap, cred) 40037737Smckusick register struct vnode *vp; 40137737Smckusick register struct vattr *vap; 40237737Smckusick register struct ucred *cred; 4036254Sroot { 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) 42037737Smckusick if (error = chown1(vp, vap->va_uid, vap->va_gid, cred)) 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 && 43037773Smckusick (error = suser(cred, &u.u_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) 44137737Smckusick error = chmod1(vp, (int)vap->va_mode, cred); 44238254Smckusick if (vap->va_flags != VNOVAL) { 44338254Smckusick if (cred->cr_uid != ip->i_uid && 44438254Smckusick (error = suser(cred, &u.u_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 */ 46137737Smckusick chmod1(vp, mode, cred) 46237737Smckusick register struct vnode *vp; 4637701Ssam register int mode; 46437737Smckusick struct ucred *cred; 4657701Ssam { 46637737Smckusick register struct inode *ip = VTOI(vp); 46737773Smckusick int error; 4687868Sroot 46937773Smckusick if (cred->cr_uid != ip->i_uid && 47037773Smckusick (error = suser(cred, &u.u_acflag))) 47137773Smckusick return (error); 47237737Smckusick if (cred->cr_uid) { 47346206Smckusick if (vp->v_type != VDIR && (mode & ISVTX)) 47445783Sbostic return (EFTYPE); 47546206Smckusick if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) 47645783Sbostic return (EPERM); 4777439Sroot } 47845783Sbostic ip->i_mode &= ~07777; 47937737Smckusick ip->i_mode |= mode & 07777; 4806254Sroot ip->i_flag |= ICHG; 48137737Smckusick if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) 48245722Smckusick (void) vnode_pager_uncache(vp); 48321015Smckusick return (0); 4845992Swnj } 4855992Swnj 4869167Ssam /* 4877701Ssam * Perform chown operation on inode ip; 4887701Ssam * inode must be locked prior to call. 4897701Ssam */ 49037737Smckusick chown1(vp, uid, gid, cred) 49137737Smckusick register struct vnode *vp; 49237737Smckusick uid_t uid; 49337737Smckusick gid_t gid; 49437737Smckusick struct ucred *cred; 4957701Ssam { 49637737Smckusick register struct inode *ip = VTOI(vp); 49741312Smckusick uid_t ouid; 49841312Smckusick gid_t ogid; 49941312Smckusick int error = 0; 5007701Ssam #ifdef QUOTA 50141312Smckusick register int i; 50241312Smckusick long change; 50311811Ssam #endif 5047701Ssam 50537737Smckusick if (uid == (u_short)VNOVAL) 50611811Ssam uid = ip->i_uid; 50737737Smckusick if (gid == (u_short)VNOVAL) 50811811Ssam gid = ip->i_gid; 50936614Sbostic /* 51036614Sbostic * If we don't own the file, are trying to change the owner 51136614Sbostic * of the file, or are not a member of the target group, 51236614Sbostic * the caller must be superuser or the call fails. 51336614Sbostic */ 51437737Smckusick if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || 51537737Smckusick !groupmember((gid_t)gid, cred)) && 51637737Smckusick (error = suser(cred, &u.u_acflag))) 51737737Smckusick return (error); 51841312Smckusick ouid = ip->i_uid; 51941312Smckusick ogid = ip->i_gid; 52011811Ssam #ifdef QUOTA 52141312Smckusick if (error = getinoquota(ip)) 52241312Smckusick return (error); 52341312Smckusick if (ouid == uid) { 52441312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 52541312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 52641312Smckusick } 52741312Smckusick if (ogid == gid) { 52841312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 52941312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 53041312Smckusick } 53141312Smckusick change = ip->i_blocks; 53241312Smckusick (void) chkdq(ip, -change, cred, CHOWN); 53341312Smckusick (void) chkiq(ip, -1, cred, CHOWN); 53441312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 53541312Smckusick dqrele(vp, ip->i_dquot[i]); 53641312Smckusick ip->i_dquot[i] = NODQUOT; 53741312Smckusick } 5387482Skre #endif 53911811Ssam ip->i_uid = uid; 54011811Ssam ip->i_gid = gid; 5417701Ssam #ifdef QUOTA 54241312Smckusick if ((error = getinoquota(ip)) == 0) { 54341312Smckusick if (ouid == uid) { 54441312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 54541312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 54641312Smckusick } 54741312Smckusick if (ogid == gid) { 54841312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 54941312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 55041312Smckusick } 55141312Smckusick if ((error = chkdq(ip, change, cred, CHOWN)) == 0) { 55241312Smckusick if ((error = chkiq(ip, 1, cred, CHOWN)) == 0) 55341927Smckusick goto good; 55441312Smckusick else 55541312Smckusick (void) chkdq(ip, -change, cred, CHOWN|FORCE); 55641312Smckusick } 55741312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 55841312Smckusick dqrele(vp, ip->i_dquot[i]); 55941312Smckusick ip->i_dquot[i] = NODQUOT; 56041312Smckusick } 56141312Smckusick } 56241312Smckusick ip->i_uid = ouid; 56341312Smckusick ip->i_gid = ogid; 56441312Smckusick if (getinoquota(ip) == 0) { 56541312Smckusick if (ouid == uid) { 56641312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 56741312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 56841312Smckusick } 56941312Smckusick if (ogid == gid) { 57041312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 57141312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 57241312Smckusick } 57341927Smckusick (void) chkdq(ip, change, cred, FORCE|CHOWN); 57441927Smckusick (void) chkiq(ip, 1, cred, FORCE|CHOWN); 57542440Smckusick (void) getinoquota(ip); 57641312Smckusick } 57742440Smckusick return (error); 57841927Smckusick good: 57942440Smckusick if (getinoquota(ip)) 58042440Smckusick panic("chown: lost quota"); 58142440Smckusick #endif /* QUOTA */ 58241312Smckusick if (ouid != uid || ogid != gid) 58341312Smckusick ip->i_flag |= ICHG; 58441312Smckusick if (ouid != uid && cred->cr_uid != 0) 58541312Smckusick ip->i_mode &= ~ISUID; 58641312Smckusick if (ogid != gid && cred->cr_uid != 0) 58741312Smckusick ip->i_mode &= ~ISGID; 58812646Ssam return (0); 58937Sbill } 59037Sbill 59139608Smckusick /* 59239608Smckusick * Vnode op for reading. 59339608Smckusick */ 59437737Smckusick /* ARGSUSED */ 59539608Smckusick ufs_read(vp, uio, ioflag, cred) 59639608Smckusick struct vnode *vp; 59739608Smckusick register struct uio *uio; 59839608Smckusick int ioflag; 59939608Smckusick struct ucred *cred; 60039608Smckusick { 60139608Smckusick register struct inode *ip = VTOI(vp); 60239608Smckusick register struct fs *fs; 60339608Smckusick struct buf *bp; 60439608Smckusick daddr_t lbn, bn, rablock; 60539896Smckusick int size, diff, error = 0; 60639608Smckusick long n, on, type; 60739608Smckusick 60839608Smckusick if (uio->uio_rw != UIO_READ) 60939608Smckusick panic("ufs_read mode"); 61039608Smckusick type = ip->i_mode & IFMT; 61139608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 61239608Smckusick panic("ufs_read type"); 61339608Smckusick if (uio->uio_resid == 0) 61439608Smckusick return (0); 61539608Smckusick if (uio->uio_offset < 0) 61639608Smckusick return (EINVAL); 61739608Smckusick ip->i_flag |= IACC; 61839608Smckusick fs = ip->i_fs; 61939608Smckusick do { 62039608Smckusick lbn = lblkno(fs, uio->uio_offset); 62139608Smckusick on = blkoff(fs, uio->uio_offset); 62239608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 62339608Smckusick diff = ip->i_size - uio->uio_offset; 62439608Smckusick if (diff <= 0) 62539608Smckusick return (0); 62639608Smckusick if (diff < n) 62739608Smckusick n = diff; 62839608Smckusick size = blksize(fs, ip, lbn); 62939674Smckusick rablock = lbn + 1; 63039896Smckusick if (vp->v_lastr + 1 == lbn && 63139896Smckusick lblktosize(fs, rablock) < ip->i_size) 63239896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 63339896Smckusick blksize(fs, ip, rablock), NOCRED, &bp); 63439608Smckusick else 63539674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 63639815Smckusick vp->v_lastr = lbn; 63739608Smckusick n = MIN(n, size - bp->b_resid); 63839608Smckusick if (error) { 63939608Smckusick brelse(bp); 64039608Smckusick return (error); 64139608Smckusick } 64239608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 64339608Smckusick if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size) 64439608Smckusick bp->b_flags |= B_AGE; 64539608Smckusick brelse(bp); 64639608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 64739608Smckusick return (error); 64839608Smckusick } 64939608Smckusick 65039608Smckusick /* 65139608Smckusick * Vnode op for writing. 65239608Smckusick */ 65339608Smckusick ufs_write(vp, uio, ioflag, cred) 65439608Smckusick register struct vnode *vp; 65539608Smckusick struct uio *uio; 65639608Smckusick int ioflag; 65739608Smckusick struct ucred *cred; 65839608Smckusick { 65939608Smckusick register struct inode *ip = VTOI(vp); 66039608Smckusick register struct fs *fs; 66139608Smckusick struct buf *bp; 66239608Smckusick daddr_t lbn, bn; 66339608Smckusick u_long osize; 66445722Smckusick int n, on, flags; 66545722Smckusick int size, resid, error = 0; 66639608Smckusick 66739608Smckusick if (uio->uio_rw != UIO_WRITE) 66839608Smckusick panic("ufs_write mode"); 66939608Smckusick switch (vp->v_type) { 67039608Smckusick case VREG: 67139608Smckusick if (ioflag & IO_APPEND) 67239608Smckusick uio->uio_offset = ip->i_size; 67339608Smckusick /* fall through */ 67439608Smckusick case VLNK: 67539608Smckusick break; 67639608Smckusick 67739608Smckusick case VDIR: 67839608Smckusick if ((ioflag & IO_SYNC) == 0) 67939608Smckusick panic("ufs_write nonsync dir write"); 68039608Smckusick break; 68139608Smckusick 68239608Smckusick default: 68339608Smckusick panic("ufs_write type"); 68439608Smckusick } 68539608Smckusick if (uio->uio_offset < 0) 68639608Smckusick return (EINVAL); 68739608Smckusick if (uio->uio_resid == 0) 68839608Smckusick return (0); 68939608Smckusick /* 69039608Smckusick * Maybe this should be above the vnode op call, but so long as 69139608Smckusick * file servers have no limits, i don't think it matters 69239608Smckusick */ 69339608Smckusick if (vp->v_type == VREG && 69439608Smckusick uio->uio_offset + uio->uio_resid > 69539608Smckusick u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { 69639608Smckusick psignal(u.u_procp, SIGXFSZ); 69739608Smckusick return (EFBIG); 69839608Smckusick } 69939608Smckusick resid = uio->uio_resid; 70039608Smckusick osize = ip->i_size; 70139608Smckusick fs = ip->i_fs; 70239674Smckusick flags = 0; 70339674Smckusick if (ioflag & IO_SYNC) 70439674Smckusick flags = B_SYNC; 70539608Smckusick do { 70639608Smckusick lbn = lblkno(fs, uio->uio_offset); 70739608Smckusick on = blkoff(fs, uio->uio_offset); 70839608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 70939608Smckusick if (n < fs->fs_bsize) 71039674Smckusick flags |= B_CLRBUF; 71139608Smckusick else 71239674Smckusick flags &= ~B_CLRBUF; 71339674Smckusick if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) 71439608Smckusick break; 71539674Smckusick bn = bp->b_blkno; 71645722Smckusick if (uio->uio_offset + n > ip->i_size) { 71739608Smckusick ip->i_size = uio->uio_offset + n; 71845722Smckusick vnode_pager_setsize(vp, ip->i_size); 71945722Smckusick } 72039608Smckusick size = blksize(fs, ip, lbn); 72145722Smckusick (void) vnode_pager_uncache(vp); 72239608Smckusick n = MIN(n, size - bp->b_resid); 72339608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 72439608Smckusick if (ioflag & IO_SYNC) 72539608Smckusick (void) bwrite(bp); 72639608Smckusick else if (n + on == fs->fs_bsize) { 72739608Smckusick bp->b_flags |= B_AGE; 72839608Smckusick bawrite(bp); 72939608Smckusick } else 73039608Smckusick bdwrite(bp); 73139608Smckusick ip->i_flag |= IUPD|ICHG; 73239608Smckusick if (cred->cr_uid != 0) 73339608Smckusick ip->i_mode &= ~(ISUID|ISGID); 73439608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 73539608Smckusick if (error && (ioflag & IO_UNIT)) { 73639674Smckusick (void) itrunc(ip, osize, ioflag & IO_SYNC); 73739608Smckusick uio->uio_offset -= resid - uio->uio_resid; 73839608Smckusick uio->uio_resid = resid; 73939608Smckusick } 74042493Smckusick if (!error && (ioflag & IO_SYNC)) 74142493Smckusick error = iupdat(ip, &time, &time, 1); 74239608Smckusick return (error); 74339608Smckusick } 74439608Smckusick 74539608Smckusick /* ARGSUSED */ 74637737Smckusick ufs_ioctl(vp, com, data, fflag, cred) 74737737Smckusick struct vnode *vp; 74837737Smckusick int com; 74937737Smckusick caddr_t data; 75037737Smckusick int fflag; 75137737Smckusick struct ucred *cred; 75211811Ssam { 75311811Ssam 75437737Smckusick return (ENOTTY); 75511811Ssam } 75611811Ssam 75737737Smckusick /* ARGSUSED */ 75840290Smckusick ufs_select(vp, which, fflags, cred) 75937737Smckusick struct vnode *vp; 76040290Smckusick int which, fflags; 76137737Smckusick struct ucred *cred; 76237737Smckusick { 76337737Smckusick 76437737Smckusick return (1); /* XXX */ 76537737Smckusick } 76637737Smckusick 7679167Ssam /* 76837737Smckusick * Mmap a file 76937737Smckusick * 77037737Smckusick * NB Currently unsupported. 7719167Ssam */ 77237737Smckusick /* ARGSUSED */ 77337737Smckusick ufs_mmap(vp, fflags, cred) 77437737Smckusick struct vnode *vp; 77537737Smckusick int fflags; 77637737Smckusick struct ucred *cred; 77737Sbill { 77837Sbill 77937737Smckusick return (EINVAL); 78037Sbill } 7817535Sroot 7829167Ssam /* 78337737Smckusick * Synch an open file. 7849167Ssam */ 78537737Smckusick /* ARGSUSED */ 78639597Smckusick ufs_fsync(vp, fflags, cred, waitfor) 78737737Smckusick struct vnode *vp; 78837737Smckusick int fflags; 78937737Smckusick struct ucred *cred; 79039597Smckusick int waitfor; 7917701Ssam { 79239597Smckusick struct inode *ip = VTOI(vp); 7937701Ssam 79437737Smckusick if (fflags&FWRITE) 79537737Smckusick ip->i_flag |= ICHG; 79639674Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 79739674Smckusick return (iupdat(ip, &time, &time, waitfor == MNT_WAIT)); 7987701Ssam } 7997701Ssam 8009167Ssam /* 80137737Smckusick * Seek on a file 80237737Smckusick * 80337737Smckusick * Nothing to do, so just return. 8049167Ssam */ 80537737Smckusick /* ARGSUSED */ 80637737Smckusick ufs_seek(vp, oldoff, newoff, cred) 80737737Smckusick struct vnode *vp; 80837737Smckusick off_t oldoff, newoff; 80937737Smckusick struct ucred *cred; 8107701Ssam { 8117701Ssam 81237737Smckusick return (0); 81337737Smckusick } 81437737Smckusick 81537737Smckusick /* 81637737Smckusick * ufs remove 81737737Smckusick * Hard to avoid races here, especially 81837737Smckusick * in unlinking directories. 81937737Smckusick */ 82037737Smckusick ufs_remove(ndp) 82137737Smckusick struct nameidata *ndp; 82237737Smckusick { 82337737Smckusick register struct inode *ip, *dp; 82437737Smckusick int error; 82537737Smckusick 82637737Smckusick ip = VTOI(ndp->ni_vp); 82737737Smckusick dp = VTOI(ndp->ni_dvp); 82837737Smckusick error = dirremove(ndp); 82937737Smckusick if (!error) { 83037737Smckusick ip->i_nlink--; 83137737Smckusick ip->i_flag |= ICHG; 8327701Ssam } 83337737Smckusick if (dp == ip) 83437737Smckusick vrele(ITOV(ip)); 83537737Smckusick else 83637737Smckusick iput(ip); 83737737Smckusick iput(dp); 83837737Smckusick return (error); 8397701Ssam } 8407701Ssam 8419167Ssam /* 84237737Smckusick * link vnode call 8439167Ssam */ 84437737Smckusick ufs_link(vp, ndp) 84537737Smckusick register struct vnode *vp; 84637737Smckusick register struct nameidata *ndp; 8479167Ssam { 84837737Smckusick register struct inode *ip = VTOI(vp); 84937737Smckusick int error; 8509167Ssam 85146251Smckusick if ((unsigned short)ip->i_nlink >= LINK_MAX) 85246251Smckusick return (EMLINK); 85337737Smckusick if (ndp->ni_dvp != vp) 85437737Smckusick ILOCK(ip); 85537737Smckusick ip->i_nlink++; 85637737Smckusick ip->i_flag |= ICHG; 85737737Smckusick error = iupdat(ip, &time, &time, 1); 85837737Smckusick if (!error) 85937737Smckusick error = direnter(ip, ndp); 86037737Smckusick if (ndp->ni_dvp != vp) 86137737Smckusick IUNLOCK(ip); 862*47219Smckusick vput(ndp->ni_dvp); 86337737Smckusick if (error) { 86437737Smckusick ip->i_nlink--; 86530598Smckusick ip->i_flag |= ICHG; 86637737Smckusick } 86737737Smckusick return (error); 8689167Ssam } 8699167Ssam 8709167Ssam /* 8719167Ssam * Rename system call. 8729167Ssam * rename("foo", "bar"); 8739167Ssam * is essentially 8749167Ssam * unlink("bar"); 8759167Ssam * link("foo", "bar"); 8769167Ssam * unlink("foo"); 8779167Ssam * but ``atomically''. Can't do full commit without saving state in the 8789167Ssam * inode on disk which isn't feasible at this time. Best we can do is 8799167Ssam * always guarantee the target exists. 8809167Ssam * 8819167Ssam * Basic algorithm is: 8829167Ssam * 8839167Ssam * 1) Bump link count on source while we're linking it to the 88437737Smckusick * target. This also ensure the inode won't be deleted out 88516776Smckusick * from underneath us while we work (it may be truncated by 88616776Smckusick * a concurrent `trunc' or `open' for creation). 8879167Ssam * 2) Link source to destination. If destination already exists, 8889167Ssam * delete it first. 88916776Smckusick * 3) Unlink source reference to inode if still around. If a 89016776Smckusick * directory was moved and the parent of the destination 8919167Ssam * is different from the source, patch the ".." entry in the 8929167Ssam * directory. 8939167Ssam */ 89437737Smckusick ufs_rename(fndp, tndp) 89537737Smckusick register struct nameidata *fndp, *tndp; 8967701Ssam { 8979167Ssam register struct inode *ip, *xp, *dp; 89816776Smckusick struct dirtemplate dirbuf; 89916776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 90010051Ssam int error = 0; 9017701Ssam 90237737Smckusick dp = VTOI(fndp->ni_dvp); 90337737Smckusick ip = VTOI(fndp->ni_vp); 90437737Smckusick ILOCK(ip); 9059167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 90637737Smckusick register struct direct *d = &fndp->ni_dent; 9079167Ssam 9089167Ssam /* 90911641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 9109167Ssam */ 91137737Smckusick if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip || 91237737Smckusick fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { 91342466Smckusick VOP_ABORTOP(tndp); 91442466Smckusick vput(tndp->ni_dvp); 91542466Smckusick if (tndp->ni_vp) 91642466Smckusick vput(tndp->ni_vp); 91742466Smckusick VOP_ABORTOP(fndp); 91842466Smckusick vrele(fndp->ni_dvp); 91942466Smckusick vput(fndp->ni_vp); 92037737Smckusick return (EINVAL); 9219167Ssam } 92216776Smckusick ip->i_flag |= IRENAME; 9239167Ssam oldparent = dp->i_number; 9249167Ssam doingdirectory++; 9259167Ssam } 92637737Smckusick vrele(fndp->ni_dvp); 9279167Ssam 9289167Ssam /* 9299167Ssam * 1) Bump link count while we're moving stuff 9309167Ssam * around. If we crash somewhere before 9319167Ssam * completing our work, the link count 9329167Ssam * may be wrong, but correctable. 9339167Ssam */ 9349167Ssam ip->i_nlink++; 9359167Ssam ip->i_flag |= ICHG; 93637737Smckusick error = iupdat(ip, &time, &time, 1); 93716664Smckusick IUNLOCK(ip); 9389167Ssam 9399167Ssam /* 9409167Ssam * When the target exists, both the directory 94137737Smckusick * and target vnodes are returned locked. 9429167Ssam */ 94337737Smckusick dp = VTOI(tndp->ni_dvp); 94437737Smckusick xp = NULL; 94537737Smckusick if (tndp->ni_vp) 94637737Smckusick xp = VTOI(tndp->ni_vp); 9479167Ssam /* 94811641Ssam * If ".." must be changed (ie the directory gets a new 94912816Smckusick * parent) then the source directory must not be in the 95012816Smckusick * directory heirarchy above the target, as this would 95112816Smckusick * orphan everything below the source directory. Also 95212816Smckusick * the user must have write permission in the source so 95312816Smckusick * as to be able to change "..". We must repeat the call 95412816Smckusick * to namei, as the parent directory is unlocked by the 95512816Smckusick * call to checkpath(). 95611641Ssam */ 95716776Smckusick if (oldparent != dp->i_number) 95816776Smckusick newparent = dp->i_number; 95916776Smckusick if (doingdirectory && newparent) { 96041466Smckusick VOP_LOCK(fndp->ni_vp); 96141466Smckusick error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred); 96241466Smckusick VOP_UNLOCK(fndp->ni_vp); 96341466Smckusick if (error) 96412816Smckusick goto bad; 96546511Smckusick tndp->ni_nameiop &= ~(MODMASK | OPMASK); 96646511Smckusick tndp->ni_nameiop |= RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 96712816Smckusick do { 96837737Smckusick dp = VTOI(tndp->ni_dvp); 96912816Smckusick if (xp != NULL) 97038069Smckusick iput(xp); 97137737Smckusick if (error = checkpath(ip, dp, tndp->ni_cred)) 97212816Smckusick goto out; 97337737Smckusick if (error = namei(tndp)) 97412816Smckusick goto out; 97537737Smckusick xp = NULL; 97637737Smckusick if (tndp->ni_vp) 97737737Smckusick xp = VTOI(tndp->ni_vp); 97837737Smckusick } while (dp != VTOI(tndp->ni_dvp)); 97912816Smckusick } 98011641Ssam /* 9819167Ssam * 2) If target doesn't exist, link the target 9829167Ssam * to the source and unlink the source. 9839167Ssam * Otherwise, rewrite the target directory 9849167Ssam * entry to reference the source inode and 9859167Ssam * expunge the original entry's existence. 9869167Ssam */ 9879167Ssam if (xp == NULL) { 98837737Smckusick if (dp->i_dev != ip->i_dev) 98937737Smckusick panic("rename: EXDEV"); 9909167Ssam /* 99116776Smckusick * Account for ".." in new directory. 99216776Smckusick * When source and destination have the same 99316776Smckusick * parent we don't fool with the link count. 9949167Ssam */ 99516776Smckusick if (doingdirectory && newparent) { 99646251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 99746251Smckusick error = EMLINK; 99846251Smckusick goto bad; 99946251Smckusick } 10009167Ssam dp->i_nlink++; 10019167Ssam dp->i_flag |= ICHG; 100246251Smckusick if (error = iupdat(dp, &time, &time, 1)) 100346251Smckusick goto bad; 10049167Ssam } 1005*47219Smckusick if (error = direnter(ip, tndp)) { 1006*47219Smckusick if (doingdirectory && newparent) { 1007*47219Smckusick dp->i_nlink--; 1008*47219Smckusick dp->i_flag |= ICHG; 1009*47219Smckusick (void) iupdat(dp, &time, &time, 1); 1010*47219Smckusick } 1011*47219Smckusick goto bad; 1012*47219Smckusick } 10139167Ssam } else { 101437737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 101537737Smckusick panic("rename: EXDEV"); 10169167Ssam /* 101710590Ssam * Short circuit rename(foo, foo). 101810590Ssam */ 101910590Ssam if (xp->i_number == ip->i_number) 102037737Smckusick panic("rename: same file"); 102110590Ssam /* 102224433Sbloom * If the parent directory is "sticky", then the user must 102324433Sbloom * own the parent directory, or the destination of the rename, 102424433Sbloom * otherwise the destination may not be changed (except by 102524433Sbloom * root). This implements append-only directories. 102624433Sbloom */ 102737737Smckusick if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && 102837737Smckusick tndp->ni_cred->cr_uid != dp->i_uid && 102937737Smckusick xp->i_uid != tndp->ni_cred->cr_uid) { 103024433Sbloom error = EPERM; 103124433Sbloom goto bad; 103224433Sbloom } 103324433Sbloom /* 103410051Ssam * Target must be empty if a directory 103510051Ssam * and have no links to it. 10369167Ssam * Also, insure source and target are 10379167Ssam * compatible (both directories, or both 10389167Ssam * not directories). 10399167Ssam */ 10409167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 104137737Smckusick if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 104237737Smckusick xp->i_nlink > 2) { 104310051Ssam error = ENOTEMPTY; 10449167Ssam goto bad; 10459167Ssam } 10469167Ssam if (!doingdirectory) { 104710051Ssam error = ENOTDIR; 10489167Ssam goto bad; 10499167Ssam } 105037737Smckusick cache_purge(ITOV(dp)); 10519167Ssam } else if (doingdirectory) { 105210051Ssam error = EISDIR; 10539167Ssam goto bad; 10549167Ssam } 105537737Smckusick if (error = dirrewrite(dp, ip, tndp)) 105637737Smckusick goto bad; 105745354Smckusick /* 105845354Smckusick * If the target directory is in the same 105945354Smckusick * directory as the source directory, 106045354Smckusick * decrement the link count on the parent 106145354Smckusick * of the target directory. 106245354Smckusick */ 106345354Smckusick if (doingdirectory && !newparent) { 106445354Smckusick dp->i_nlink--; 106545354Smckusick dp->i_flag |= ICHG; 106645354Smckusick } 106737737Smckusick vput(ITOV(dp)); 10689167Ssam /* 106910051Ssam * Adjust the link count of the target to 107010051Ssam * reflect the dirrewrite above. If this is 107110051Ssam * a directory it is empty and there are 107210051Ssam * no links to it, so we can squash the inode and 107310051Ssam * any space associated with it. We disallowed 107410051Ssam * renaming over top of a directory with links to 107516776Smckusick * it above, as the remaining link would point to 107616776Smckusick * a directory without "." or ".." entries. 10779167Ssam */ 107810051Ssam xp->i_nlink--; 10799167Ssam if (doingdirectory) { 108010051Ssam if (--xp->i_nlink != 0) 108110051Ssam panic("rename: linked directory"); 108239674Smckusick error = itrunc(xp, (u_long)0, IO_SYNC); 108310051Ssam } 10849167Ssam xp->i_flag |= ICHG; 108538398Smckusick iput(xp); 108610246Ssam xp = NULL; 10879167Ssam } 10889167Ssam 10899167Ssam /* 10909167Ssam * 3) Unlink the source. 10919167Ssam */ 109246511Smckusick fndp->ni_nameiop &= ~(MODMASK | OPMASK); 109346511Smckusick fndp->ni_nameiop |= DELETE | LOCKPARENT | LOCKLEAF; 109437737Smckusick (void)namei(fndp); 109537737Smckusick if (fndp->ni_vp != NULL) { 109637737Smckusick xp = VTOI(fndp->ni_vp); 109737737Smckusick dp = VTOI(fndp->ni_dvp); 109837737Smckusick } else { 109946250Smckusick /* 110046250Smckusick * From name has disappeared. 110146250Smckusick */ 110246250Smckusick if (doingdirectory) 110346250Smckusick panic("rename: lost dir entry"); 110446250Smckusick vrele(ITOV(ip)); 110546250Smckusick return (0); 110637737Smckusick } 11079167Ssam /* 110837737Smckusick * Ensure that the directory entry still exists and has not 110916776Smckusick * changed while the new name has been entered. If the source is 111016776Smckusick * a file then the entry may have been unlinked or renamed. In 111116776Smckusick * either case there is no further work to be done. If the source 111216776Smckusick * is a directory then it cannot have been rmdir'ed; its link 111316776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 111437737Smckusick * The IRENAME flag ensures that it cannot be moved by another 111516776Smckusick * rename. 11169167Ssam */ 111717758Smckusick if (xp != ip) { 111816776Smckusick if (doingdirectory) 111917758Smckusick panic("rename: lost dir entry"); 112016776Smckusick } else { 11219167Ssam /* 112216776Smckusick * If the source is a directory with a 112316776Smckusick * new parent, the link count of the old 112416776Smckusick * parent directory must be decremented 112516776Smckusick * and ".." set to point to the new parent. 11269167Ssam */ 112716776Smckusick if (doingdirectory && newparent) { 11289167Ssam dp->i_nlink--; 11299167Ssam dp->i_flag |= ICHG; 113039597Smckusick error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, 113137737Smckusick sizeof (struct dirtemplate), (off_t)0, 113239597Smckusick UIO_SYSSPACE, IO_NODELOCKED, 113339597Smckusick tndp->ni_cred, (int *)0); 113416776Smckusick if (error == 0) { 113516776Smckusick if (dirbuf.dotdot_namlen != 2 || 113616776Smckusick dirbuf.dotdot_name[0] != '.' || 113716776Smckusick dirbuf.dotdot_name[1] != '.') { 113839610Smckusick dirbad(xp, 12, "rename: mangled dir"); 113916776Smckusick } else { 114016776Smckusick dirbuf.dotdot_ino = newparent; 114139597Smckusick (void) vn_rdwr(UIO_WRITE, ITOV(xp), 114216776Smckusick (caddr_t)&dirbuf, 114316776Smckusick sizeof (struct dirtemplate), 114437740Smckusick (off_t)0, UIO_SYSSPACE, 114539597Smckusick IO_NODELOCKED|IO_SYNC, 114637737Smckusick tndp->ni_cred, (int *)0); 114737737Smckusick cache_purge(ITOV(dp)); 114816776Smckusick } 114916776Smckusick } 11509167Ssam } 115137737Smckusick error = dirremove(fndp); 115237737Smckusick if (!error) { 115316776Smckusick xp->i_nlink--; 115416776Smckusick xp->i_flag |= ICHG; 11559167Ssam } 115616776Smckusick xp->i_flag &= ~IRENAME; 11579167Ssam } 11589167Ssam if (dp) 115937737Smckusick vput(ITOV(dp)); 116016776Smckusick if (xp) 116137737Smckusick vput(ITOV(xp)); 116237737Smckusick vrele(ITOV(ip)); 116337737Smckusick return (error); 11649167Ssam 11659167Ssam bad: 11669167Ssam if (xp) 116737737Smckusick vput(ITOV(xp)); 116837737Smckusick vput(ITOV(dp)); 11699167Ssam out: 11709167Ssam ip->i_nlink--; 11719167Ssam ip->i_flag |= ICHG; 117237737Smckusick vrele(ITOV(ip)); 117337737Smckusick return (error); 11747701Ssam } 11757701Ssam 11767535Sroot /* 117712756Ssam * A virgin directory (no blushing please). 117812756Ssam */ 117912756Ssam struct dirtemplate mastertemplate = { 118012756Ssam 0, 12, 1, ".", 118112756Ssam 0, DIRBLKSIZ - 12, 2, ".." 118212756Ssam }; 118312756Ssam 118412756Ssam /* 118512756Ssam * Mkdir system call 118612756Ssam */ 118737737Smckusick ufs_mkdir(ndp, vap) 118837737Smckusick struct nameidata *ndp; 118937737Smckusick struct vattr *vap; 119012756Ssam { 119112756Ssam register struct inode *ip, *dp; 119237737Smckusick struct inode *tip; 119337737Smckusick struct vnode *dvp; 119412756Ssam struct dirtemplate dirtemplate; 119537737Smckusick int error; 119637737Smckusick int dmode; 119712756Ssam 119837737Smckusick dvp = ndp->ni_dvp; 119937737Smckusick dp = VTOI(dvp); 120046251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 120146251Smckusick iput(dp); 120246251Smckusick return (EMLINK); 120346251Smckusick } 120437737Smckusick dmode = vap->va_mode&0777; 120537737Smckusick dmode |= IFDIR; 120612756Ssam /* 120712756Ssam * Must simulate part of maknode here 120812756Ssam * in order to acquire the inode, but 120912756Ssam * not have it entered in the parent 121012756Ssam * directory. The entry is made later 121112756Ssam * after writing "." and ".." entries out. 121212756Ssam */ 121341312Smckusick if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { 121412756Ssam iput(dp); 121537737Smckusick return (error); 121612756Ssam } 121737737Smckusick ip = tip; 121841312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 121941312Smckusick ip->i_gid = dp->i_gid; 122012756Ssam #ifdef QUOTA 122141312Smckusick if ((error = getinoquota(ip)) || 122241312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 122341312Smckusick ifree(ip, ip->i_number, dmode); 122441312Smckusick iput(ip); 122541312Smckusick iput(dp); 122641312Smckusick return (error); 122741312Smckusick } 122812756Ssam #endif 122912756Ssam ip->i_flag |= IACC|IUPD|ICHG; 123037737Smckusick ip->i_mode = dmode; 123137737Smckusick ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ 123212756Ssam ip->i_nlink = 2; 123337737Smckusick error = iupdat(ip, &time, &time, 1); 123412756Ssam 123512756Ssam /* 123612756Ssam * Bump link count in parent directory 123712756Ssam * to reflect work done below. Should 123812756Ssam * be done before reference is created 123912756Ssam * so reparation is possible if we crash. 124012756Ssam */ 124112756Ssam dp->i_nlink++; 124212756Ssam dp->i_flag |= ICHG; 1243*47219Smckusick if (error = iupdat(dp, &time, &time, 1)) 1244*47219Smckusick goto bad; 124512756Ssam 124612756Ssam /* 124712756Ssam * Initialize directory with "." 124812756Ssam * and ".." from static template. 124912756Ssam */ 125012756Ssam dirtemplate = mastertemplate; 125112756Ssam dirtemplate.dot_ino = ip->i_number; 125212756Ssam dirtemplate.dotdot_ino = dp->i_number; 125339597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, 125437737Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 125539597Smckusick IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0); 125637737Smckusick if (error) { 125712756Ssam dp->i_nlink--; 125812756Ssam dp->i_flag |= ICHG; 125912756Ssam goto bad; 126012756Ssam } 126143288Smckusick if (DIRBLKSIZ > dp->i_fs->fs_fsize) { 126237737Smckusick panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ 126343288Smckusick } else { 126418103Smckusick ip->i_size = DIRBLKSIZ; 126543288Smckusick ip->i_flag |= ICHG; 126643288Smckusick } 126712756Ssam /* 126812756Ssam * Directory all set up, now 126912756Ssam * install the entry for it in 127012756Ssam * the parent directory. 127112756Ssam */ 1272*47219Smckusick if (error = direnter(ip, ndp)) { 127346511Smckusick ndp->ni_nameiop &= ~(MODMASK | OPMASK); 1274*47219Smckusick ndp->ni_nameiop |= LOOKUP | LOCKLEAF | NOCACHE; 127537737Smckusick error = namei(ndp); 127637737Smckusick if (!error) { 1277*47219Smckusick iput(dp); 127837737Smckusick dp = VTOI(ndp->ni_vp); 127912756Ssam dp->i_nlink--; 128012756Ssam dp->i_flag |= ICHG; 128112756Ssam } 128212756Ssam } 128312756Ssam bad: 128412756Ssam /* 128512756Ssam * No need to do an explicit itrunc here, 128637737Smckusick * vrele will do this for us because we set 128712756Ssam * the link count to 0. 128812756Ssam */ 128937737Smckusick if (error) { 129012756Ssam ip->i_nlink = 0; 129112756Ssam ip->i_flag |= ICHG; 129238144Smckusick iput(ip); 129338144Smckusick } else 129438144Smckusick ndp->ni_vp = ITOV(ip); 1295*47219Smckusick iput(dp); 129637737Smckusick return (error); 129712756Ssam } 129812756Ssam 129912756Ssam /* 130012756Ssam * Rmdir system call. 130112756Ssam */ 130237737Smckusick ufs_rmdir(ndp) 130337737Smckusick register struct nameidata *ndp; 130412756Ssam { 130512756Ssam register struct inode *ip, *dp; 130637737Smckusick int error = 0; 130712756Ssam 130837737Smckusick ip = VTOI(ndp->ni_vp); 130937737Smckusick dp = VTOI(ndp->ni_dvp); 131012756Ssam /* 131112756Ssam * No rmdir "." please. 131212756Ssam */ 131312756Ssam if (dp == ip) { 131437737Smckusick vrele(ITOV(dp)); 131512756Ssam iput(ip); 131637737Smckusick return (EINVAL); 131712756Ssam } 131812756Ssam /* 131912756Ssam * Verify the directory is empty (and valid). 132012756Ssam * (Rmdir ".." won't be valid since 132112756Ssam * ".." will contain a reference to 132212756Ssam * the current directory and thus be 132312756Ssam * non-empty.) 132412756Ssam */ 132537737Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { 132637737Smckusick error = ENOTEMPTY; 132712756Ssam goto out; 132812756Ssam } 132912756Ssam /* 133012756Ssam * Delete reference to directory before purging 133112756Ssam * inode. If we crash in between, the directory 133212756Ssam * will be reattached to lost+found, 133312756Ssam */ 133437737Smckusick if (error = dirremove(ndp)) 133512756Ssam goto out; 133612756Ssam dp->i_nlink--; 133712756Ssam dp->i_flag |= ICHG; 133837737Smckusick cache_purge(ITOV(dp)); 133912756Ssam iput(dp); 134037737Smckusick ndp->ni_dvp = NULL; 134112756Ssam /* 134212756Ssam * Truncate inode. The only stuff left 134312756Ssam * in the directory is "." and "..". The 134412756Ssam * "." reference is inconsequential since 134512756Ssam * we're quashing it. The ".." reference 134612756Ssam * has already been adjusted above. We've 134712756Ssam * removed the "." reference and the reference 134812756Ssam * in the parent directory, but there may be 134912756Ssam * other hard links so decrement by 2 and 135012756Ssam * worry about them later. 135112756Ssam */ 135212756Ssam ip->i_nlink -= 2; 135339674Smckusick error = itrunc(ip, (u_long)0, IO_SYNC); 135437737Smckusick cache_purge(ITOV(ip)); 135512756Ssam out: 135637737Smckusick if (ndp->ni_dvp) 135712756Ssam iput(dp); 135812756Ssam iput(ip); 135937737Smckusick return (error); 136012756Ssam } 136112756Ssam 136237737Smckusick /* 136337737Smckusick * symlink -- make a symbolic link 136437737Smckusick */ 136537737Smckusick ufs_symlink(ndp, vap, target) 136637737Smckusick struct nameidata *ndp; 136737737Smckusick struct vattr *vap; 136837737Smckusick char *target; 136912756Ssam { 137037737Smckusick struct inode *ip; 137137737Smckusick int error; 137212756Ssam 137337737Smckusick error = maknode(IFLNK | vap->va_mode, ndp, &ip); 137437737Smckusick if (error) 137537737Smckusick return (error); 137639597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, 137739597Smckusick UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0); 137837737Smckusick iput(ip); 137937737Smckusick return (error); 138037737Smckusick } 138137737Smckusick 138237737Smckusick /* 138337737Smckusick * Vnode op for read and write 138437737Smckusick */ 138540345Smckusick ufs_readdir(vp, uio, cred, eofflagp) 138637737Smckusick struct vnode *vp; 138737737Smckusick register struct uio *uio; 138837737Smckusick struct ucred *cred; 138940345Smckusick int *eofflagp; 139037737Smckusick { 139139597Smckusick int count, lost, error; 139237737Smckusick 139337737Smckusick count = uio->uio_resid; 139437737Smckusick count &= ~(DIRBLKSIZ - 1); 139539597Smckusick lost = uio->uio_resid - count; 139639597Smckusick if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) 139737737Smckusick return (EINVAL); 139837737Smckusick uio->uio_resid = count; 139937737Smckusick uio->uio_iov->iov_len = count; 140039597Smckusick error = ufs_read(vp, uio, 0, cred); 140139597Smckusick uio->uio_resid += lost; 140240345Smckusick if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) 140340345Smckusick *eofflagp = 1; 140440345Smckusick else 140540345Smckusick *eofflagp = 0; 140637737Smckusick return (error); 140737737Smckusick } 140837737Smckusick 140937737Smckusick /* 141037737Smckusick * Return target name of a symbolic link 141137737Smckusick */ 141237737Smckusick ufs_readlink(vp, uiop, cred) 141337737Smckusick struct vnode *vp; 141437737Smckusick struct uio *uiop; 141537737Smckusick struct ucred *cred; 141637737Smckusick { 141737737Smckusick 141839597Smckusick return (ufs_read(vp, uiop, 0, cred)); 141937737Smckusick } 142037737Smckusick 142137737Smckusick /* 142237737Smckusick * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 142342466Smckusick * done. Nothing to do at the moment. 142437737Smckusick */ 142542466Smckusick /* ARGSUSED */ 142637737Smckusick ufs_abortop(ndp) 142742466Smckusick struct nameidata *ndp; 142837737Smckusick { 142937737Smckusick 143042466Smckusick return (0); 143112756Ssam } 143212756Ssam 143339909Smckusick /* 143439909Smckusick * Lock an inode. 143539909Smckusick */ 143637737Smckusick ufs_lock(vp) 143737737Smckusick struct vnode *vp; 143837737Smckusick { 143937737Smckusick register struct inode *ip = VTOI(vp); 144037737Smckusick 144137737Smckusick ILOCK(ip); 144237737Smckusick return (0); 144337737Smckusick } 144437737Smckusick 144539909Smckusick /* 144639909Smckusick * Unlock an inode. 144739909Smckusick */ 144837737Smckusick ufs_unlock(vp) 144937737Smckusick struct vnode *vp; 145037737Smckusick { 145137737Smckusick register struct inode *ip = VTOI(vp); 145237737Smckusick 145337737Smckusick if (!(ip->i_flag & ILOCKED)) 145437737Smckusick panic("ufs_unlock NOT LOCKED"); 145537737Smckusick IUNLOCK(ip); 145637737Smckusick return (0); 145737737Smckusick } 145837737Smckusick 145912756Ssam /* 146039909Smckusick * Check for a locked inode. 146139909Smckusick */ 146239909Smckusick ufs_islocked(vp) 146339909Smckusick struct vnode *vp; 146439909Smckusick { 146539909Smckusick 146639909Smckusick if (VTOI(vp)->i_flag & ILOCKED) 146739909Smckusick return (1); 146839909Smckusick return (0); 146939909Smckusick } 147039909Smckusick 147139909Smckusick /* 147237737Smckusick * Get access to bmap 147312756Ssam */ 147437737Smckusick ufs_bmap(vp, bn, vpp, bnp) 147537737Smckusick struct vnode *vp; 147637737Smckusick daddr_t bn; 147737737Smckusick struct vnode **vpp; 147837737Smckusick daddr_t *bnp; 147912756Ssam { 148037737Smckusick struct inode *ip = VTOI(vp); 148112756Ssam 148237737Smckusick if (vpp != NULL) 148337737Smckusick *vpp = ip->i_devvp; 148437737Smckusick if (bnp == NULL) 148537737Smckusick return (0); 148641538Smckusick return (bmap(ip, bn, bnp)); 148712756Ssam } 148837737Smckusick 148937737Smckusick /* 149041538Smckusick * Calculate the logical to physical mapping if not done already, 149141538Smckusick * then call the device strategy routine. 149237737Smckusick */ 149341538Smckusick int checkoverlap = 0; 149439674Smckusick 149537737Smckusick ufs_strategy(bp) 149637737Smckusick register struct buf *bp; 149737737Smckusick { 149839674Smckusick register struct inode *ip = VTOI(bp->b_vp); 149939674Smckusick struct vnode *vp; 150039674Smckusick int error; 150139674Smckusick 150239674Smckusick if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 150339674Smckusick panic("ufs_strategy: spec"); 150439674Smckusick if (bp->b_blkno == bp->b_lblkno) { 150539674Smckusick if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno)) 150639674Smckusick return (error); 150739896Smckusick if ((long)bp->b_blkno == -1) 150839674Smckusick clrbuf(bp); 150939674Smckusick } 151039896Smckusick if ((long)bp->b_blkno == -1) { 151139896Smckusick biodone(bp); 151239674Smckusick return (0); 151339896Smckusick } 151441538Smckusick #ifdef DIAGNOSTIC 151539674Smckusick if (checkoverlap) { 151641538Smckusick register struct buf *ep; 151741538Smckusick struct buf *ebp; 151841538Smckusick daddr_t start, last; 151941538Smckusick 152039674Smckusick ebp = &buf[nbuf]; 152139674Smckusick start = bp->b_blkno; 152239674Smckusick last = start + btodb(bp->b_bcount) - 1; 152339674Smckusick for (ep = buf; ep < ebp; ep++) { 152439674Smckusick if (ep == bp || (ep->b_flags & B_INVAL) || 152541396Smckusick ep->b_vp == NULLVP) 152639674Smckusick continue; 152739674Smckusick if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0)) 152839674Smckusick continue; 152939674Smckusick if (vp != ip->i_devvp) 153039674Smckusick continue; 153139674Smckusick /* look for overlap */ 153239674Smckusick if (ep->b_bcount == 0 || ep->b_blkno > last || 153339674Smckusick ep->b_blkno + btodb(ep->b_bcount) <= start) 153439674Smckusick continue; 153539896Smckusick vprint("Disk overlap", vp); 153639896Smckusick printf("\tstart %d, end %d overlap start %d, end %d\n", 153739896Smckusick start, last, ep->b_blkno, 153839896Smckusick ep->b_blkno + btodb(ep->b_bcount) - 1); 153941538Smckusick panic("Disk buffer overlap"); 154039674Smckusick } 154139674Smckusick } 154241538Smckusick #endif /* DIAGNOSTIC */ 154339674Smckusick vp = ip->i_devvp; 154439674Smckusick bp->b_dev = vp->v_rdev; 154539674Smckusick (*(vp->v_op->vn_strategy))(bp); 154637737Smckusick return (0); 154737737Smckusick } 154837737Smckusick 154937737Smckusick /* 155039674Smckusick * Print out the contents of an inode. 155139674Smckusick */ 155239674Smckusick ufs_print(vp) 155339674Smckusick struct vnode *vp; 155439674Smckusick { 155539674Smckusick register struct inode *ip = VTOI(vp); 155639674Smckusick 155740293Smckusick printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number, 155840293Smckusick major(ip->i_dev), minor(ip->i_dev)); 155940293Smckusick #ifdef FIFO 156040293Smckusick if (vp->v_type == VFIFO) 156140293Smckusick fifo_printinfo(vp); 156240293Smckusick #endif /* FIFO */ 156340293Smckusick printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : ""); 156439900Smckusick if (ip->i_spare0 == 0) 156539900Smckusick return; 156639900Smckusick printf("\towner pid %d", ip->i_spare0); 156739900Smckusick if (ip->i_spare1) 156839900Smckusick printf(" waiting pid %d", ip->i_spare1); 156939900Smckusick printf("\n"); 157039674Smckusick } 157139674Smckusick 157239674Smckusick /* 157339628Smckusick * Read wrapper for special devices. 157439628Smckusick */ 157539628Smckusick ufsspec_read(vp, uio, ioflag, cred) 157639628Smckusick struct vnode *vp; 157739628Smckusick struct uio *uio; 157839628Smckusick int ioflag; 157939628Smckusick struct ucred *cred; 158039628Smckusick { 158139628Smckusick 158239628Smckusick /* 158339628Smckusick * Set access flag. 158439628Smckusick */ 158539628Smckusick VTOI(vp)->i_flag |= IACC; 158639628Smckusick return (spec_read(vp, uio, ioflag, cred)); 158739628Smckusick } 158839628Smckusick 158939628Smckusick /* 159039628Smckusick * Write wrapper for special devices. 159139628Smckusick */ 159239628Smckusick ufsspec_write(vp, uio, ioflag, cred) 159339628Smckusick struct vnode *vp; 159439628Smckusick struct uio *uio; 159539628Smckusick int ioflag; 159639628Smckusick struct ucred *cred; 159739628Smckusick { 159839628Smckusick 159939628Smckusick /* 160039628Smckusick * Set update and change flags. 160139628Smckusick */ 160239628Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 160339628Smckusick return (spec_write(vp, uio, ioflag, cred)); 160439628Smckusick } 160539628Smckusick 160639628Smckusick /* 160739628Smckusick * Close wrapper for special devices. 160839628Smckusick * 160939628Smckusick * Update the times on the inode then do device close. 161039628Smckusick */ 161139628Smckusick ufsspec_close(vp, fflag, cred) 161239628Smckusick struct vnode *vp; 161339628Smckusick int fflag; 161439628Smckusick struct ucred *cred; 161539628Smckusick { 161639628Smckusick register struct inode *ip = VTOI(vp); 161739628Smckusick 161839815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 161939628Smckusick ITIMES(ip, &time, &time); 162039628Smckusick return (spec_close(vp, fflag, cred)); 162139628Smckusick } 162239628Smckusick 162340290Smckusick #ifdef FIFO 162439628Smckusick /* 162540290Smckusick * Read wrapper for fifo's 162640290Smckusick */ 162740290Smckusick ufsfifo_read(vp, uio, ioflag, cred) 162840290Smckusick struct vnode *vp; 162940290Smckusick struct uio *uio; 163040290Smckusick int ioflag; 163140290Smckusick struct ucred *cred; 163240290Smckusick { 163340290Smckusick 163440290Smckusick /* 163540290Smckusick * Set access flag. 163640290Smckusick */ 163740290Smckusick VTOI(vp)->i_flag |= IACC; 163840290Smckusick return (fifo_read(vp, uio, ioflag, cred)); 163940290Smckusick } 164040290Smckusick 164140290Smckusick /* 164240290Smckusick * Write wrapper for fifo's. 164340290Smckusick */ 164440290Smckusick ufsfifo_write(vp, uio, ioflag, cred) 164540290Smckusick struct vnode *vp; 164640290Smckusick struct uio *uio; 164740290Smckusick int ioflag; 164840290Smckusick struct ucred *cred; 164940290Smckusick { 165040290Smckusick 165140290Smckusick /* 165240290Smckusick * Set update and change flags. 165340290Smckusick */ 165440290Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 165540290Smckusick return (fifo_write(vp, uio, ioflag, cred)); 165640290Smckusick } 165740290Smckusick 165840290Smckusick /* 165940290Smckusick * Close wrapper for fifo's. 166040290Smckusick * 166140290Smckusick * Update the times on the inode then do device close. 166240290Smckusick */ 166340290Smckusick ufsfifo_close(vp, fflag, cred) 166440290Smckusick struct vnode *vp; 166540290Smckusick int fflag; 166640290Smckusick struct ucred *cred; 166740290Smckusick { 166840290Smckusick register struct inode *ip = VTOI(vp); 166940290Smckusick 167040290Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 167140290Smckusick ITIMES(ip, &time, &time); 167240290Smckusick return (fifo_close(vp, fflag, cred)); 167340290Smckusick } 167440290Smckusick #endif /* FIFO */ 167540290Smckusick 167640290Smckusick /* 167737737Smckusick * Make a new file. 167837737Smckusick */ 167937737Smckusick maknode(mode, ndp, ipp) 168037737Smckusick int mode; 168137737Smckusick register struct nameidata *ndp; 168237737Smckusick struct inode **ipp; 168337737Smckusick { 168437737Smckusick register struct inode *ip; 168537737Smckusick struct inode *tip; 168637737Smckusick register struct inode *pdir = VTOI(ndp->ni_dvp); 168737737Smckusick ino_t ipref; 168837737Smckusick int error; 168937737Smckusick 169037737Smckusick *ipp = 0; 169141312Smckusick if ((mode & IFMT) == 0) 169241312Smckusick mode |= IFREG; 169337737Smckusick if ((mode & IFMT) == IFDIR) 169437737Smckusick ipref = dirpref(pdir->i_fs); 169537737Smckusick else 169637737Smckusick ipref = pdir->i_number; 169741312Smckusick if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { 169837737Smckusick iput(pdir); 169937737Smckusick return (error); 170037737Smckusick } 170137737Smckusick ip = tip; 170241312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 170341312Smckusick ip->i_gid = pdir->i_gid; 170437737Smckusick #ifdef QUOTA 170541312Smckusick if ((error = getinoquota(ip)) || 170641312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 170741312Smckusick ifree(ip, ip->i_number, mode); 170841312Smckusick iput(ip); 170941312Smckusick iput(pdir); 171041312Smckusick return (error); 171141312Smckusick } 171237737Smckusick #endif 171337737Smckusick ip->i_flag |= IACC|IUPD|ICHG; 171437737Smckusick ip->i_mode = mode; 171537737Smckusick ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ 171637737Smckusick ip->i_nlink = 1; 171737737Smckusick if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && 171837737Smckusick suser(ndp->ni_cred, NULL)) 171937737Smckusick ip->i_mode &= ~ISGID; 172037737Smckusick 172137737Smckusick /* 172237737Smckusick * Make sure inode goes to disk before directory entry. 172337737Smckusick */ 172441312Smckusick if (error = iupdat(ip, &time, &time, 1)) 172541312Smckusick goto bad; 1726*47219Smckusick if (error = direnter(ip, ndp)) 172741312Smckusick goto bad; 1728*47219Smckusick iput(pdir); 172937737Smckusick *ipp = ip; 173037737Smckusick return (0); 173141312Smckusick 173241312Smckusick bad: 173341312Smckusick /* 173441312Smckusick * Write error occurred trying to update the inode 173541312Smckusick * or the directory so must deallocate the inode. 173641312Smckusick */ 1737*47219Smckusick iput(pdir); 173841312Smckusick ip->i_nlink = 0; 173941312Smckusick ip->i_flag |= ICHG; 174041312Smckusick iput(ip); 174141312Smckusick return (error); 174237737Smckusick } 174346207Smckusick 174446207Smckusick /* 174546207Smckusick * Advisory record locking support 174646207Smckusick */ 174746207Smckusick ufs_advlock(vp, id, op, fl, flags) 174846207Smckusick struct vnode *vp; 174946207Smckusick caddr_t id; 175046207Smckusick int op; 175146207Smckusick register struct flock *fl; 175246207Smckusick int flags; 175346207Smckusick { 175446207Smckusick register struct inode *ip = VTOI(vp); 175546207Smckusick register struct lockf *lock; 175646207Smckusick off_t start, end; 175746207Smckusick int error; 175846207Smckusick 175946207Smckusick /* 176046207Smckusick * Avoid the common case of unlocking when inode has no locks. 176146207Smckusick */ 176246207Smckusick if (ip->i_lockf == (struct lockf *)0) { 176346207Smckusick if (op != F_SETLK) { 176446207Smckusick fl->l_type = F_UNLCK; 176546207Smckusick return (0); 176646207Smckusick } 176746207Smckusick } 176846207Smckusick /* 176946207Smckusick * Convert the flock structure into a start and end. 177046207Smckusick */ 177146207Smckusick switch (fl->l_whence) { 177246207Smckusick 177346207Smckusick case SEEK_SET: 177446207Smckusick case SEEK_CUR: 177546207Smckusick /* 177646207Smckusick * Caller is responsible for adding any necessary offset 177746207Smckusick * when SEEK_CUR is used. 177846207Smckusick */ 177946207Smckusick start = fl->l_start; 178046207Smckusick break; 178146207Smckusick 178246207Smckusick case SEEK_END: 178346207Smckusick start = ip->i_size + fl->l_start; 178446207Smckusick break; 178546207Smckusick 178646207Smckusick default: 178746207Smckusick return (EINVAL); 178846207Smckusick } 178946207Smckusick if (start < 0) 179046207Smckusick return (EINVAL); 179146207Smckusick if (fl->l_len == 0) 179246207Smckusick end = -1; 179346207Smckusick else 179446507Smckusick end = start + fl->l_len - 1; 179546207Smckusick /* 179646207Smckusick * Create the lockf structure 179746207Smckusick */ 179846207Smckusick MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); 179946207Smckusick lock->lf_start = start; 180046207Smckusick lock->lf_end = end; 180146207Smckusick lock->lf_id = id; 180246207Smckusick lock->lf_inode = ip; 180346207Smckusick lock->lf_type = fl->l_type; 180446207Smckusick lock->lf_next = (struct lockf *)0; 180546207Smckusick lock->lf_block = (struct lockf *)0; 180646207Smckusick lock->lf_flags = flags; 180746207Smckusick /* 180846207Smckusick * Do the requested operation. 180946207Smckusick */ 181046207Smckusick switch(op) { 181146207Smckusick case F_SETLK: 181246679Smckusick return (lf_setlock(lock)); 181346207Smckusick 181446207Smckusick case F_UNLCK: 181546679Smckusick error = lf_clearlock(lock); 181646679Smckusick FREE(lock, M_LOCKF); 181746679Smckusick return (error); 181846207Smckusick 181946207Smckusick case F_GETLK: 182046679Smckusick error = lf_getlock(lock, fl); 182146679Smckusick FREE(lock, M_LOCKF); 182246679Smckusick return (error); 182346207Smckusick 182446207Smckusick default: 182546207Smckusick free(lock, M_LOCKF); 182646207Smckusick return (EINVAL); 182746207Smckusick } 182846207Smckusick /* NOTREACHED */ 182946207Smckusick } 1830