123405Smckusick /* 237737Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337737Smckusick * All rights reserved. 423405Smckusick * 537737Smckusick * Redistribution and use in source and binary forms are permitted 637737Smckusick * provided that the above copyright notice and this paragraph are 737737Smckusick * duplicated in all such forms and that any documentation, 837737Smckusick * advertising materials, and other materials related to such 937737Smckusick * distribution and use acknowledge that the software was developed 1037737Smckusick * by the University of California, Berkeley. The name of the 1137737Smckusick * University may not be used to endorse or promote products derived 1237737Smckusick * from this software without specific prior written permission. 1337737Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437737Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537737Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637737Smckusick * 17*40653Smckusick * @(#)lfs_vnops.c 7.35 (Berkeley) 03/27/90 1823405Smckusick */ 1937Sbill 2017101Sbloom #include "param.h" 2117101Sbloom #include "systm.h" 2217101Sbloom #include "user.h" 2317101Sbloom #include "kernel.h" 2417101Sbloom #include "file.h" 2517101Sbloom #include "stat.h" 2617101Sbloom #include "buf.h" 2717101Sbloom #include "proc.h" 2817101Sbloom #include "socket.h" 2917101Sbloom #include "socketvar.h" 3037737Smckusick #include "conf.h" 3117101Sbloom #include "mount.h" 3237737Smckusick #include "vnode.h" 33*40653Smckusick #include "specdev.h" 3437737Smckusick #include "../ufs/inode.h" 3537737Smckusick #include "../ufs/fs.h" 3637737Smckusick #include "../ufs/quota.h" 3737Sbill 389167Ssam /* 3937737Smckusick * Global vfs data structures for ufs 409167Ssam */ 416254Sroot 4237737Smckusick int ufs_lookup(), 4337737Smckusick ufs_create(), 4437737Smckusick ufs_mknod(), 4537737Smckusick ufs_open(), 4637737Smckusick ufs_close(), 4737737Smckusick ufs_access(), 4837737Smckusick ufs_getattr(), 4937737Smckusick ufs_setattr(), 5037737Smckusick ufs_read(), 5137737Smckusick ufs_write(), 5237737Smckusick ufs_ioctl(), 5337737Smckusick ufs_select(), 5437737Smckusick ufs_mmap(), 5537737Smckusick ufs_fsync(), 5637737Smckusick ufs_seek(), 5737737Smckusick ufs_remove(), 5837737Smckusick ufs_link(), 5937737Smckusick ufs_rename(), 6037737Smckusick ufs_mkdir(), 6137737Smckusick ufs_rmdir(), 6237737Smckusick ufs_symlink(), 6337737Smckusick ufs_readdir(), 6437737Smckusick ufs_readlink(), 6537737Smckusick ufs_abortop(), 6637737Smckusick ufs_inactive(), 6739391Smckusick ufs_reclaim(), 6837737Smckusick ufs_lock(), 6937737Smckusick ufs_unlock(), 7037737Smckusick ufs_bmap(), 7139674Smckusick ufs_strategy(), 7239909Smckusick ufs_print(), 7339909Smckusick ufs_islocked(); 746254Sroot 7537737Smckusick struct vnodeops ufs_vnodeops = { 7639674Smckusick ufs_lookup, /* lookup */ 7739674Smckusick ufs_create, /* create */ 7839674Smckusick ufs_mknod, /* mknod */ 7939674Smckusick ufs_open, /* open */ 8039674Smckusick ufs_close, /* close */ 8139674Smckusick ufs_access, /* access */ 8239674Smckusick ufs_getattr, /* getattr */ 8339674Smckusick ufs_setattr, /* setattr */ 8439674Smckusick ufs_read, /* read */ 8539674Smckusick ufs_write, /* write */ 8639674Smckusick ufs_ioctl, /* ioctl */ 8739674Smckusick ufs_select, /* select */ 8839674Smckusick ufs_mmap, /* mmap */ 8939674Smckusick ufs_fsync, /* fsync */ 9039674Smckusick ufs_seek, /* seek */ 9139674Smckusick ufs_remove, /* remove */ 9239674Smckusick ufs_link, /* link */ 9339674Smckusick ufs_rename, /* rename */ 9439674Smckusick ufs_mkdir, /* mkdir */ 9539674Smckusick ufs_rmdir, /* rmdir */ 9639674Smckusick ufs_symlink, /* symlink */ 9739674Smckusick ufs_readdir, /* readdir */ 9839674Smckusick ufs_readlink, /* readlink */ 9939674Smckusick ufs_abortop, /* abortop */ 10039674Smckusick ufs_inactive, /* inactive */ 10139674Smckusick ufs_reclaim, /* reclaim */ 10239674Smckusick ufs_lock, /* lock */ 10339674Smckusick ufs_unlock, /* unlock */ 10439674Smckusick ufs_bmap, /* bmap */ 10539674Smckusick ufs_strategy, /* strategy */ 10639674Smckusick ufs_print, /* print */ 10739909Smckusick ufs_islocked, /* islocked */ 10837737Smckusick }; 1096254Sroot 11039435Smckusick int spec_lookup(), 11139435Smckusick spec_open(), 11239628Smckusick ufsspec_read(), 11339628Smckusick ufsspec_write(), 11439435Smckusick spec_strategy(), 11539674Smckusick spec_bmap(), 11639435Smckusick spec_ioctl(), 11739435Smckusick spec_select(), 11839628Smckusick ufsspec_close(), 11939435Smckusick spec_badop(), 12039435Smckusick spec_nullop(); 12139435Smckusick 12239435Smckusick struct vnodeops spec_inodeops = { 12339597Smckusick spec_lookup, /* lookup */ 12439597Smckusick spec_badop, /* create */ 12539597Smckusick spec_badop, /* mknod */ 12639597Smckusick spec_open, /* open */ 12739628Smckusick ufsspec_close, /* close */ 12839597Smckusick ufs_access, /* access */ 12939597Smckusick ufs_getattr, /* getattr */ 13039597Smckusick ufs_setattr, /* setattr */ 13139628Smckusick ufsspec_read, /* read */ 13239628Smckusick ufsspec_write, /* write */ 13339597Smckusick spec_ioctl, /* ioctl */ 13439597Smckusick spec_select, /* select */ 13539597Smckusick spec_badop, /* mmap */ 13639597Smckusick spec_nullop, /* fsync */ 13739597Smckusick spec_badop, /* seek */ 13839597Smckusick spec_badop, /* remove */ 13939597Smckusick spec_badop, /* link */ 14039597Smckusick spec_badop, /* rename */ 14139597Smckusick spec_badop, /* mkdir */ 14239597Smckusick spec_badop, /* rmdir */ 14339597Smckusick spec_badop, /* symlink */ 14439597Smckusick spec_badop, /* readdir */ 14539597Smckusick spec_badop, /* readlink */ 14639597Smckusick spec_badop, /* abortop */ 14739597Smckusick ufs_inactive, /* inactive */ 14839597Smckusick ufs_reclaim, /* reclaim */ 14939597Smckusick ufs_lock, /* lock */ 15039597Smckusick ufs_unlock, /* unlock */ 15139674Smckusick spec_bmap, /* bmap */ 15239597Smckusick spec_strategy, /* strategy */ 15339674Smckusick ufs_print, /* print */ 15439909Smckusick ufs_islocked, /* islocked */ 15539435Smckusick }; 15639435Smckusick 15740290Smckusick #ifdef FIFO 15840290Smckusick int fifo_lookup(), 15940290Smckusick fifo_open(), 16040290Smckusick ufsfifo_read(), 16140290Smckusick ufsfifo_write(), 16240290Smckusick fifo_bmap(), 16340290Smckusick fifo_ioctl(), 16440290Smckusick fifo_select(), 16540290Smckusick ufsfifo_close(), 16640290Smckusick fifo_print(), 16740290Smckusick fifo_badop(), 16840290Smckusick fifo_nullop(); 16940290Smckusick 17040290Smckusick struct vnodeops fifo_inodeops = { 17140290Smckusick fifo_lookup, /* lookup */ 17240290Smckusick fifo_badop, /* create */ 17340290Smckusick fifo_badop, /* mknod */ 17440290Smckusick fifo_open, /* open */ 17540290Smckusick ufsfifo_close, /* close */ 17640290Smckusick ufs_access, /* access */ 17740290Smckusick ufs_getattr, /* getattr */ 17840290Smckusick ufs_setattr, /* setattr */ 17940290Smckusick ufsfifo_read, /* read */ 18040290Smckusick ufsfifo_write, /* write */ 18140290Smckusick fifo_ioctl, /* ioctl */ 18240290Smckusick fifo_select, /* select */ 18340290Smckusick fifo_badop, /* mmap */ 18440290Smckusick fifo_nullop, /* fsync */ 18540290Smckusick fifo_badop, /* seek */ 18640290Smckusick fifo_badop, /* remove */ 18740290Smckusick fifo_badop, /* link */ 18840290Smckusick fifo_badop, /* rename */ 18940290Smckusick fifo_badop, /* mkdir */ 19040290Smckusick fifo_badop, /* rmdir */ 19140290Smckusick fifo_badop, /* symlink */ 19240290Smckusick fifo_badop, /* readdir */ 19340290Smckusick fifo_badop, /* readlink */ 19440290Smckusick fifo_badop, /* abortop */ 19540290Smckusick ufs_inactive, /* inactive */ 19640290Smckusick ufs_reclaim, /* reclaim */ 19740290Smckusick ufs_lock, /* lock */ 19840290Smckusick ufs_unlock, /* unlock */ 19940290Smckusick fifo_bmap, /* bmap */ 20040290Smckusick fifo_badop, /* strategy */ 20140290Smckusick ufs_print, /* print */ 20240290Smckusick ufs_islocked, /* islocked */ 20337737Smckusick }; 20440290Smckusick #endif /* FIFO */ 20540290Smckusick 20640290Smckusick enum vtype iftovt_tab[16] = { 20740290Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 20840290Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 20937737Smckusick }; 21040290Smckusick int vttoif_tab[9] = { 21140290Smckusick 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT, 21240290Smckusick }; 2136254Sroot 2149167Ssam /* 21537737Smckusick * Create a regular file 2169167Ssam */ 21737737Smckusick ufs_create(ndp, vap) 21837737Smckusick struct nameidata *ndp; 21937737Smckusick struct vattr *vap; 2206254Sroot { 22137737Smckusick struct inode *ip; 22237737Smckusick int error; 2236254Sroot 22437737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 22537737Smckusick return (error); 22637737Smckusick ndp->ni_vp = ITOV(ip); 22737737Smckusick return (0); 2286254Sroot } 2296254Sroot 23037Sbill /* 23137737Smckusick * Mknod vnode call 2326254Sroot */ 23337737Smckusick /* ARGSUSED */ 23437737Smckusick ufs_mknod(ndp, vap, cred) 23537737Smckusick struct nameidata *ndp; 23637737Smckusick struct ucred *cred; 23737737Smckusick struct vattr *vap; 2386254Sroot { 23939435Smckusick register struct vnode *vp; 24037737Smckusick struct inode *ip; 24137737Smckusick int error; 2426254Sroot 24337737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 24437737Smckusick return (error); 24540290Smckusick ip->i_flag |= IACC|IUPD|ICHG; 24640290Smckusick if (vap->va_rdev != VNOVAL) { 24737737Smckusick /* 24837737Smckusick * Want to be able to use this to make badblock 24937737Smckusick * inodes, so don't truncate the dev number. 25037737Smckusick */ 25139608Smckusick ip->i_rdev = vap->va_rdev; 25212756Ssam } 25337737Smckusick /* 25437737Smckusick * Remove inode so that it will be reloaded by iget and 25537737Smckusick * checked to see if it is an alias of an existing entry 25637737Smckusick * in the inode cache. 25737737Smckusick */ 25840290Smckusick vp = ITOV(ip); 25940290Smckusick vput(vp); 26039435Smckusick vp->v_type = VNON; 26139435Smckusick vgone(vp); 26237737Smckusick return (0); 2636254Sroot } 2646254Sroot 2656254Sroot /* 26637737Smckusick * Open called. 26737737Smckusick * 26837737Smckusick * Nothing to do. 2696254Sroot */ 27037737Smckusick /* ARGSUSED */ 27137737Smckusick ufs_open(vp, mode, cred) 27237737Smckusick struct vnode *vp; 27337737Smckusick int mode; 27437737Smckusick struct ucred *cred; 2756254Sroot { 2766254Sroot 27737737Smckusick return (0); 2786254Sroot } 2796254Sroot 2806254Sroot /* 28137737Smckusick * Close called 28237737Smckusick * 28337737Smckusick * Update the times on the inode. 2846254Sroot */ 28537737Smckusick /* ARGSUSED */ 28637737Smckusick ufs_close(vp, fflag, cred) 28737737Smckusick struct vnode *vp; 28837737Smckusick int fflag; 28937737Smckusick struct ucred *cred; 2906254Sroot { 29137737Smckusick register struct inode *ip = VTOI(vp); 2926254Sroot 29339815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 29437737Smckusick ITIMES(ip, &time, &time); 29537737Smckusick return (0); 2966254Sroot } 2976254Sroot 29837737Smckusick ufs_access(vp, mode, cred) 29937737Smckusick struct vnode *vp; 30037737Smckusick int mode; 30137737Smckusick struct ucred *cred; 3026254Sroot { 3036254Sroot 30437737Smckusick return (iaccess(VTOI(vp), mode, cred)); 3056254Sroot } 3066254Sroot 30737737Smckusick /* ARGSUSED */ 30837737Smckusick ufs_getattr(vp, vap, cred) 30937737Smckusick struct vnode *vp; 31037737Smckusick register struct vattr *vap; 31137737Smckusick struct ucred *cred; 3126254Sroot { 31337737Smckusick register struct inode *ip = VTOI(vp); 3146254Sroot 31537737Smckusick ITIMES(ip, &time, &time); 3166254Sroot /* 31737737Smckusick * Copy from inode table 3186254Sroot */ 31937737Smckusick vap->va_fsid = ip->i_dev; 32037737Smckusick vap->va_fileid = ip->i_number; 32137737Smckusick vap->va_mode = ip->i_mode & ~IFMT; 32237737Smckusick vap->va_nlink = ip->i_nlink; 32337737Smckusick vap->va_uid = ip->i_uid; 32437737Smckusick vap->va_gid = ip->i_gid; 32537737Smckusick vap->va_rdev = (dev_t)ip->i_rdev; 32640641Smckusick vap->va_qsize = ip->i_din.di_qsize; 32737737Smckusick vap->va_atime.tv_sec = ip->i_atime; 32838578Smckusick vap->va_atime.tv_usec = 0; 32937737Smckusick vap->va_mtime.tv_sec = ip->i_mtime; 33038578Smckusick vap->va_mtime.tv_usec = 0; 33137737Smckusick vap->va_ctime.tv_sec = ip->i_ctime; 33238578Smckusick vap->va_ctime.tv_usec = 0; 33338254Smckusick vap->va_flags = ip->i_flags; 33438254Smckusick vap->va_gen = ip->i_gen; 33537737Smckusick /* this doesn't belong here */ 33637737Smckusick if (vp->v_type == VBLK) 33737737Smckusick vap->va_blocksize = BLKDEV_IOSIZE; 33837737Smckusick else if (vp->v_type == VCHR) 33937737Smckusick vap->va_blocksize = MAXBSIZE; 3407142Smckusick else 34137737Smckusick vap->va_blocksize = ip->i_fs->fs_bsize; 34238657Smckusick vap->va_bytes = dbtob(ip->i_blocks); 34340641Smckusick vap->va_bytes_rsv = 0; 34437737Smckusick vap->va_type = vp->v_type; 34537737Smckusick return (0); 3466254Sroot } 3476254Sroot 3486254Sroot /* 34937737Smckusick * Set attribute vnode op. called from several syscalls 3506254Sroot */ 35137737Smckusick ufs_setattr(vp, vap, cred) 35237737Smckusick register struct vnode *vp; 35337737Smckusick register struct vattr *vap; 35437737Smckusick register struct ucred *cred; 3556254Sroot { 35637737Smckusick register struct inode *ip = VTOI(vp); 35737737Smckusick int error = 0; 3586254Sroot 35937737Smckusick /* 36037737Smckusick * Check for unsetable attributes. 36137737Smckusick */ 36237737Smckusick if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 36337737Smckusick (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 36437737Smckusick (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 36538254Smckusick ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 36637737Smckusick return (EINVAL); 36716540Ssam } 36837737Smckusick /* 36937737Smckusick * Go through the fields and update iff not VNOVAL. 37037737Smckusick */ 37137737Smckusick if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) 37237737Smckusick if (error = chown1(vp, vap->va_uid, vap->va_gid, cred)) 37337737Smckusick return (error); 37437737Smckusick if (vap->va_size != VNOVAL) { 37537737Smckusick if (vp->v_type == VDIR) 37637737Smckusick return (EISDIR); 37739674Smckusick if (error = itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */ 37837737Smckusick return (error); 37913878Ssam } 38037737Smckusick if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 38137773Smckusick if (cred->cr_uid != ip->i_uid && 38237773Smckusick (error = suser(cred, &u.u_acflag))) 38337773Smckusick return (error); 38437737Smckusick if (vap->va_atime.tv_sec != VNOVAL) 38537737Smckusick ip->i_flag |= IACC; 38637737Smckusick if (vap->va_mtime.tv_sec != VNOVAL) 38737737Smckusick ip->i_flag |= IUPD; 38837737Smckusick ip->i_flag |= ICHG; 38937737Smckusick if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) 39037737Smckusick return (error); 3916254Sroot } 39237737Smckusick if (vap->va_mode != (u_short)VNOVAL) 39337737Smckusick error = chmod1(vp, (int)vap->va_mode, cred); 39438254Smckusick if (vap->va_flags != VNOVAL) { 39538254Smckusick if (cred->cr_uid != ip->i_uid && 39638254Smckusick (error = suser(cred, &u.u_acflag))) 39738254Smckusick return (error); 39838254Smckusick if (cred->cr_uid == 0) { 39938254Smckusick ip->i_flags = vap->va_flags; 40038254Smckusick } else { 40138254Smckusick ip->i_flags &= 0xffff0000; 40238254Smckusick ip->i_flags |= (vap->va_flags & 0xffff); 40338254Smckusick } 40438254Smckusick ip->i_flag |= ICHG; 40538254Smckusick } 40637737Smckusick return (error); 4076254Sroot } 4086254Sroot 4096254Sroot /* 4109167Ssam * Change the mode on a file. 4119167Ssam * Inode must be locked before calling. 4129167Ssam */ 41337737Smckusick chmod1(vp, mode, cred) 41437737Smckusick register struct vnode *vp; 4157701Ssam register int mode; 41637737Smckusick struct ucred *cred; 4177701Ssam { 41837737Smckusick register struct inode *ip = VTOI(vp); 41937773Smckusick int error; 4207868Sroot 42137773Smckusick if (cred->cr_uid != ip->i_uid && 42237773Smckusick (error = suser(cred, &u.u_acflag))) 42337773Smckusick return (error); 4246254Sroot ip->i_mode &= ~07777; 42537737Smckusick if (cred->cr_uid) { 42637737Smckusick if (vp->v_type != VDIR) 42721015Smckusick mode &= ~ISVTX; 42837737Smckusick if (!groupmember(ip->i_gid, cred)) 42911811Ssam mode &= ~ISGID; 4307439Sroot } 43137737Smckusick ip->i_mode |= mode & 07777; 4326254Sroot ip->i_flag |= ICHG; 43337737Smckusick if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) 43437737Smckusick xrele(vp); 43521015Smckusick return (0); 4365992Swnj } 4375992Swnj 4389167Ssam /* 4397701Ssam * Perform chown operation on inode ip; 4407701Ssam * inode must be locked prior to call. 4417701Ssam */ 44237737Smckusick chown1(vp, uid, gid, cred) 44337737Smckusick register struct vnode *vp; 44437737Smckusick uid_t uid; 44537737Smckusick gid_t gid; 44637737Smckusick struct ucred *cred; 4477701Ssam { 44837737Smckusick register struct inode *ip = VTOI(vp); 4497701Ssam #ifdef QUOTA 4507701Ssam register long change; 45111811Ssam #endif 45237737Smckusick int error; 4537701Ssam 45437737Smckusick if (uid == (u_short)VNOVAL) 45511811Ssam uid = ip->i_uid; 45637737Smckusick if (gid == (u_short)VNOVAL) 45711811Ssam gid = ip->i_gid; 45836614Sbostic /* 45936614Sbostic * If we don't own the file, are trying to change the owner 46036614Sbostic * of the file, or are not a member of the target group, 46136614Sbostic * the caller must be superuser or the call fails. 46236614Sbostic */ 46337737Smckusick if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || 46437737Smckusick !groupmember((gid_t)gid, cred)) && 46537737Smckusick (error = suser(cred, &u.u_acflag))) 46637737Smckusick return (error); 46711811Ssam #ifdef QUOTA 46814385Ssam if (ip->i_uid == uid) /* this just speeds things a little */ 4697482Skre change = 0; 47012646Ssam else 47112646Ssam change = ip->i_blocks; 47212646Ssam (void) chkdq(ip, -change, 1); 47312646Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 1); 4747482Skre dqrele(ip->i_dquot); 4757482Skre #endif 47639306Smckusick if (ip->i_uid != uid && cred->cr_uid != 0) 47739306Smckusick ip->i_mode &= ~ISUID; 47839306Smckusick if (ip->i_gid != gid && cred->cr_uid != 0) 47939306Smckusick ip->i_mode &= ~ISGID; 48011811Ssam ip->i_uid = uid; 48111811Ssam ip->i_gid = gid; 4826254Sroot ip->i_flag |= ICHG; 4837701Ssam #ifdef QUOTA 4847482Skre ip->i_dquot = inoquota(ip); 48512646Ssam (void) chkdq(ip, change, 1); 48626361Skarels (void) chkiq(ip->i_dev, (struct inode *)NULL, (uid_t)uid, 1); 48712646Ssam return (u.u_error); /* should == 0 ALWAYS !! */ 48812646Ssam #else 48912646Ssam return (0); 4907482Skre #endif 49137Sbill } 49237Sbill 49339608Smckusick /* 49439608Smckusick * Vnode op for reading. 49539608Smckusick */ 49637737Smckusick /* ARGSUSED */ 49739608Smckusick ufs_read(vp, uio, ioflag, cred) 49839608Smckusick struct vnode *vp; 49939608Smckusick register struct uio *uio; 50039608Smckusick int ioflag; 50139608Smckusick struct ucred *cred; 50239608Smckusick { 50339608Smckusick register struct inode *ip = VTOI(vp); 50439608Smckusick register struct fs *fs; 50539608Smckusick struct buf *bp; 50639608Smckusick daddr_t lbn, bn, rablock; 50739896Smckusick int size, diff, error = 0; 50839608Smckusick long n, on, type; 50939608Smckusick 51039608Smckusick if (uio->uio_rw != UIO_READ) 51139608Smckusick panic("ufs_read mode"); 51239608Smckusick type = ip->i_mode & IFMT; 51339608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 51439608Smckusick panic("ufs_read type"); 51539608Smckusick if (uio->uio_resid == 0) 51639608Smckusick return (0); 51739608Smckusick if (uio->uio_offset < 0) 51839608Smckusick return (EINVAL); 51939608Smckusick ip->i_flag |= IACC; 52039608Smckusick fs = ip->i_fs; 52139608Smckusick do { 52239608Smckusick lbn = lblkno(fs, uio->uio_offset); 52339608Smckusick on = blkoff(fs, uio->uio_offset); 52439608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 52539608Smckusick diff = ip->i_size - uio->uio_offset; 52639608Smckusick if (diff <= 0) 52739608Smckusick return (0); 52839608Smckusick if (diff < n) 52939608Smckusick n = diff; 53039608Smckusick size = blksize(fs, ip, lbn); 53139674Smckusick rablock = lbn + 1; 53239896Smckusick if (vp->v_lastr + 1 == lbn && 53339896Smckusick lblktosize(fs, rablock) < ip->i_size) 53439896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 53539896Smckusick blksize(fs, ip, rablock), NOCRED, &bp); 53639608Smckusick else 53739674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 53839815Smckusick vp->v_lastr = lbn; 53939608Smckusick n = MIN(n, size - bp->b_resid); 54039608Smckusick if (error) { 54139608Smckusick brelse(bp); 54239608Smckusick return (error); 54339608Smckusick } 54439608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 54539608Smckusick if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size) 54639608Smckusick bp->b_flags |= B_AGE; 54739608Smckusick brelse(bp); 54839608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 54939608Smckusick return (error); 55039608Smckusick } 55139608Smckusick 55239608Smckusick /* 55339608Smckusick * Vnode op for writing. 55439608Smckusick */ 55539608Smckusick ufs_write(vp, uio, ioflag, cred) 55639608Smckusick register struct vnode *vp; 55739608Smckusick struct uio *uio; 55839608Smckusick int ioflag; 55939608Smckusick struct ucred *cred; 56039608Smckusick { 56139608Smckusick register struct inode *ip = VTOI(vp); 56239608Smckusick register struct fs *fs; 56339608Smckusick struct buf *bp; 56439608Smckusick daddr_t lbn, bn; 56539608Smckusick u_long osize; 56639608Smckusick int i, n, on, flags; 56739608Smckusick int count, size, resid, error = 0; 56839608Smckusick 56939608Smckusick if (uio->uio_rw != UIO_WRITE) 57039608Smckusick panic("ufs_write mode"); 57139608Smckusick switch (vp->v_type) { 57239608Smckusick case VREG: 57339608Smckusick if (ioflag & IO_APPEND) 57439608Smckusick uio->uio_offset = ip->i_size; 57539608Smckusick /* fall through */ 57639608Smckusick case VLNK: 57739608Smckusick break; 57839608Smckusick 57939608Smckusick case VDIR: 58039608Smckusick if ((ioflag & IO_SYNC) == 0) 58139608Smckusick panic("ufs_write nonsync dir write"); 58239608Smckusick break; 58339608Smckusick 58439608Smckusick default: 58539608Smckusick panic("ufs_write type"); 58639608Smckusick } 58739608Smckusick if (uio->uio_offset < 0) 58839608Smckusick return (EINVAL); 58939608Smckusick if (uio->uio_resid == 0) 59039608Smckusick return (0); 59139608Smckusick /* 59239608Smckusick * Maybe this should be above the vnode op call, but so long as 59339608Smckusick * file servers have no limits, i don't think it matters 59439608Smckusick */ 59539608Smckusick if (vp->v_type == VREG && 59639608Smckusick uio->uio_offset + uio->uio_resid > 59739608Smckusick u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { 59839608Smckusick psignal(u.u_procp, SIGXFSZ); 59939608Smckusick return (EFBIG); 60039608Smckusick } 60139608Smckusick resid = uio->uio_resid; 60239608Smckusick osize = ip->i_size; 60339608Smckusick fs = ip->i_fs; 60439674Smckusick flags = 0; 60539674Smckusick if (ioflag & IO_SYNC) 60639674Smckusick flags = B_SYNC; 60739608Smckusick do { 60839608Smckusick lbn = lblkno(fs, uio->uio_offset); 60939608Smckusick on = blkoff(fs, uio->uio_offset); 61039608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 61139608Smckusick if (n < fs->fs_bsize) 61239674Smckusick flags |= B_CLRBUF; 61339608Smckusick else 61439674Smckusick flags &= ~B_CLRBUF; 61539674Smckusick if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) 61639608Smckusick break; 61739674Smckusick bn = bp->b_blkno; 61839608Smckusick if (uio->uio_offset + n > ip->i_size) 61939608Smckusick ip->i_size = uio->uio_offset + n; 62039608Smckusick size = blksize(fs, ip, lbn); 62139608Smckusick count = howmany(size, CLBYTES); 62239608Smckusick for (i = 0; i < count; i++) 62339608Smckusick munhash(ip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); 62439608Smckusick n = MIN(n, size - bp->b_resid); 62539608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 62639608Smckusick if (ioflag & IO_SYNC) 62739608Smckusick (void) bwrite(bp); 62839608Smckusick else if (n + on == fs->fs_bsize) { 62939608Smckusick bp->b_flags |= B_AGE; 63039608Smckusick bawrite(bp); 63139608Smckusick } else 63239608Smckusick bdwrite(bp); 63339608Smckusick ip->i_flag |= IUPD|ICHG; 63439608Smckusick if (cred->cr_uid != 0) 63539608Smckusick ip->i_mode &= ~(ISUID|ISGID); 63639608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 63739608Smckusick if (error && (ioflag & IO_UNIT)) { 63839674Smckusick (void) itrunc(ip, osize, ioflag & IO_SYNC); 63939608Smckusick uio->uio_offset -= resid - uio->uio_resid; 64039608Smckusick uio->uio_resid = resid; 64139608Smckusick } 64239608Smckusick return (error); 64339608Smckusick } 64439608Smckusick 64539608Smckusick /* ARGSUSED */ 64637737Smckusick ufs_ioctl(vp, com, data, fflag, cred) 64737737Smckusick struct vnode *vp; 64837737Smckusick int com; 64937737Smckusick caddr_t data; 65037737Smckusick int fflag; 65137737Smckusick struct ucred *cred; 65211811Ssam { 65311811Ssam 65437737Smckusick return (ENOTTY); 65511811Ssam } 65611811Ssam 65737737Smckusick /* ARGSUSED */ 65840290Smckusick ufs_select(vp, which, fflags, cred) 65937737Smckusick struct vnode *vp; 66040290Smckusick int which, fflags; 66137737Smckusick struct ucred *cred; 66237737Smckusick { 66337737Smckusick 66437737Smckusick return (1); /* XXX */ 66537737Smckusick } 66637737Smckusick 6679167Ssam /* 66837737Smckusick * Mmap a file 66937737Smckusick * 67037737Smckusick * NB Currently unsupported. 6719167Ssam */ 67237737Smckusick /* ARGSUSED */ 67337737Smckusick ufs_mmap(vp, fflags, cred) 67437737Smckusick struct vnode *vp; 67537737Smckusick int fflags; 67637737Smckusick struct ucred *cred; 67737Sbill { 67837Sbill 67937737Smckusick return (EINVAL); 68037Sbill } 6817535Sroot 6829167Ssam /* 68337737Smckusick * Synch an open file. 6849167Ssam */ 68537737Smckusick /* ARGSUSED */ 68639597Smckusick ufs_fsync(vp, fflags, cred, waitfor) 68737737Smckusick struct vnode *vp; 68837737Smckusick int fflags; 68937737Smckusick struct ucred *cred; 69039597Smckusick int waitfor; 6917701Ssam { 69239597Smckusick struct inode *ip = VTOI(vp); 6937701Ssam 69437737Smckusick if (fflags&FWRITE) 69537737Smckusick ip->i_flag |= ICHG; 69639674Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 69739674Smckusick return (iupdat(ip, &time, &time, waitfor == MNT_WAIT)); 6987701Ssam } 6997701Ssam 7009167Ssam /* 70137737Smckusick * Seek on a file 70237737Smckusick * 70337737Smckusick * Nothing to do, so just return. 7049167Ssam */ 70537737Smckusick /* ARGSUSED */ 70637737Smckusick ufs_seek(vp, oldoff, newoff, cred) 70737737Smckusick struct vnode *vp; 70837737Smckusick off_t oldoff, newoff; 70937737Smckusick struct ucred *cred; 7107701Ssam { 7117701Ssam 71237737Smckusick return (0); 71337737Smckusick } 71437737Smckusick 71537737Smckusick /* 71637737Smckusick * ufs remove 71737737Smckusick * Hard to avoid races here, especially 71837737Smckusick * in unlinking directories. 71937737Smckusick */ 72037737Smckusick ufs_remove(ndp) 72137737Smckusick struct nameidata *ndp; 72237737Smckusick { 72337737Smckusick register struct inode *ip, *dp; 72437737Smckusick int error; 72537737Smckusick 72637737Smckusick ip = VTOI(ndp->ni_vp); 72737737Smckusick dp = VTOI(ndp->ni_dvp); 72837737Smckusick error = dirremove(ndp); 72937737Smckusick if (!error) { 73037737Smckusick ip->i_nlink--; 73137737Smckusick ip->i_flag |= ICHG; 7327701Ssam } 73337737Smckusick if (dp == ip) 73437737Smckusick vrele(ITOV(ip)); 73537737Smckusick else 73637737Smckusick iput(ip); 73737737Smckusick iput(dp); 73837737Smckusick return (error); 7397701Ssam } 7407701Ssam 7419167Ssam /* 74237737Smckusick * link vnode call 7439167Ssam */ 74437737Smckusick ufs_link(vp, ndp) 74537737Smckusick register struct vnode *vp; 74637737Smckusick register struct nameidata *ndp; 7479167Ssam { 74837737Smckusick register struct inode *ip = VTOI(vp); 74937737Smckusick int error; 7509167Ssam 75137737Smckusick if (ndp->ni_dvp != vp) 75237737Smckusick ILOCK(ip); 75337737Smckusick if (ip->i_nlink == LINK_MAX - 1) { 75437737Smckusick error = EMLINK; 75537737Smckusick goto out; 75637737Smckusick } 75737737Smckusick ip->i_nlink++; 75837737Smckusick ip->i_flag |= ICHG; 75937737Smckusick error = iupdat(ip, &time, &time, 1); 76037737Smckusick if (!error) 76137737Smckusick error = direnter(ip, ndp); 76237737Smckusick out: 76337737Smckusick if (ndp->ni_dvp != vp) 76437737Smckusick IUNLOCK(ip); 76537737Smckusick if (error) { 76637737Smckusick ip->i_nlink--; 76730598Smckusick ip->i_flag |= ICHG; 76837737Smckusick } 76937737Smckusick return (error); 7709167Ssam } 7719167Ssam 7729167Ssam /* 7739167Ssam * Rename system call. 7749167Ssam * rename("foo", "bar"); 7759167Ssam * is essentially 7769167Ssam * unlink("bar"); 7779167Ssam * link("foo", "bar"); 7789167Ssam * unlink("foo"); 7799167Ssam * but ``atomically''. Can't do full commit without saving state in the 7809167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7819167Ssam * always guarantee the target exists. 7829167Ssam * 7839167Ssam * Basic algorithm is: 7849167Ssam * 7859167Ssam * 1) Bump link count on source while we're linking it to the 78637737Smckusick * target. This also ensure the inode won't be deleted out 78716776Smckusick * from underneath us while we work (it may be truncated by 78816776Smckusick * a concurrent `trunc' or `open' for creation). 7899167Ssam * 2) Link source to destination. If destination already exists, 7909167Ssam * delete it first. 79116776Smckusick * 3) Unlink source reference to inode if still around. If a 79216776Smckusick * directory was moved and the parent of the destination 7939167Ssam * is different from the source, patch the ".." entry in the 7949167Ssam * directory. 7959167Ssam */ 79637737Smckusick ufs_rename(fndp, tndp) 79737737Smckusick register struct nameidata *fndp, *tndp; 7987701Ssam { 7999167Ssam register struct inode *ip, *xp, *dp; 80016776Smckusick struct dirtemplate dirbuf; 80116776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 80210051Ssam int error = 0; 8037701Ssam 80437737Smckusick dp = VTOI(fndp->ni_dvp); 80537737Smckusick ip = VTOI(fndp->ni_vp); 80637737Smckusick ILOCK(ip); 8079167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 80837737Smckusick register struct direct *d = &fndp->ni_dent; 8099167Ssam 8109167Ssam /* 81111641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 8129167Ssam */ 81337737Smckusick if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip || 81437737Smckusick fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { 81537737Smckusick IUNLOCK(ip); 81637737Smckusick ufs_abortop(fndp); 81737737Smckusick ufs_abortop(tndp); 81837737Smckusick return (EINVAL); 8199167Ssam } 82016776Smckusick ip->i_flag |= IRENAME; 8219167Ssam oldparent = dp->i_number; 8229167Ssam doingdirectory++; 8239167Ssam } 82437737Smckusick vrele(fndp->ni_dvp); 8259167Ssam 8269167Ssam /* 8279167Ssam * 1) Bump link count while we're moving stuff 8289167Ssam * around. If we crash somewhere before 8299167Ssam * completing our work, the link count 8309167Ssam * may be wrong, but correctable. 8319167Ssam */ 8329167Ssam ip->i_nlink++; 8339167Ssam ip->i_flag |= ICHG; 83437737Smckusick error = iupdat(ip, &time, &time, 1); 83516664Smckusick IUNLOCK(ip); 8369167Ssam 8379167Ssam /* 8389167Ssam * When the target exists, both the directory 83937737Smckusick * and target vnodes are returned locked. 8409167Ssam */ 84137737Smckusick dp = VTOI(tndp->ni_dvp); 84237737Smckusick xp = NULL; 84337737Smckusick if (tndp->ni_vp) 84437737Smckusick xp = VTOI(tndp->ni_vp); 8459167Ssam /* 84611641Ssam * If ".." must be changed (ie the directory gets a new 84712816Smckusick * parent) then the source directory must not be in the 84812816Smckusick * directory heirarchy above the target, as this would 84912816Smckusick * orphan everything below the source directory. Also 85012816Smckusick * the user must have write permission in the source so 85112816Smckusick * as to be able to change "..". We must repeat the call 85212816Smckusick * to namei, as the parent directory is unlocked by the 85312816Smckusick * call to checkpath(). 85411641Ssam */ 85516776Smckusick if (oldparent != dp->i_number) 85616776Smckusick newparent = dp->i_number; 85716776Smckusick if (doingdirectory && newparent) { 85837737Smckusick if (error = iaccess(ip, IWRITE, tndp->ni_cred)) 85912816Smckusick goto bad; 86037737Smckusick tndp->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 86112816Smckusick do { 86237737Smckusick dp = VTOI(tndp->ni_dvp); 86312816Smckusick if (xp != NULL) 86438069Smckusick iput(xp); 86537737Smckusick if (error = checkpath(ip, dp, tndp->ni_cred)) 86612816Smckusick goto out; 86737737Smckusick if (error = namei(tndp)) 86812816Smckusick goto out; 86937737Smckusick xp = NULL; 87037737Smckusick if (tndp->ni_vp) 87137737Smckusick xp = VTOI(tndp->ni_vp); 87237737Smckusick } while (dp != VTOI(tndp->ni_dvp)); 87312816Smckusick } 87411641Ssam /* 8759167Ssam * 2) If target doesn't exist, link the target 8769167Ssam * to the source and unlink the source. 8779167Ssam * Otherwise, rewrite the target directory 8789167Ssam * entry to reference the source inode and 8799167Ssam * expunge the original entry's existence. 8809167Ssam */ 8819167Ssam if (xp == NULL) { 88237737Smckusick if (dp->i_dev != ip->i_dev) 88337737Smckusick panic("rename: EXDEV"); 8849167Ssam /* 88516776Smckusick * Account for ".." in new directory. 88616776Smckusick * When source and destination have the same 88716776Smckusick * parent we don't fool with the link count. 8889167Ssam */ 88916776Smckusick if (doingdirectory && newparent) { 8909167Ssam dp->i_nlink++; 8919167Ssam dp->i_flag |= ICHG; 89237737Smckusick error = iupdat(dp, &time, &time, 1); 8939167Ssam } 89437737Smckusick if (error = direnter(ip, tndp)) 8959167Ssam goto out; 8969167Ssam } else { 89737737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 89837737Smckusick panic("rename: EXDEV"); 8999167Ssam /* 90010590Ssam * Short circuit rename(foo, foo). 90110590Ssam */ 90210590Ssam if (xp->i_number == ip->i_number) 90337737Smckusick panic("rename: same file"); 90410590Ssam /* 90524433Sbloom * If the parent directory is "sticky", then the user must 90624433Sbloom * own the parent directory, or the destination of the rename, 90724433Sbloom * otherwise the destination may not be changed (except by 90824433Sbloom * root). This implements append-only directories. 90924433Sbloom */ 91037737Smckusick if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && 91137737Smckusick tndp->ni_cred->cr_uid != dp->i_uid && 91237737Smckusick xp->i_uid != tndp->ni_cred->cr_uid) { 91324433Sbloom error = EPERM; 91424433Sbloom goto bad; 91524433Sbloom } 91624433Sbloom /* 91710051Ssam * Target must be empty if a directory 91810051Ssam * and have no links to it. 9199167Ssam * Also, insure source and target are 9209167Ssam * compatible (both directories, or both 9219167Ssam * not directories). 9229167Ssam */ 9239167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 92437737Smckusick if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 92537737Smckusick xp->i_nlink > 2) { 92610051Ssam error = ENOTEMPTY; 9279167Ssam goto bad; 9289167Ssam } 9299167Ssam if (!doingdirectory) { 93010051Ssam error = ENOTDIR; 9319167Ssam goto bad; 9329167Ssam } 93337737Smckusick cache_purge(ITOV(dp)); 9349167Ssam } else if (doingdirectory) { 93510051Ssam error = EISDIR; 9369167Ssam goto bad; 9379167Ssam } 93837737Smckusick if (error = dirrewrite(dp, ip, tndp)) 93937737Smckusick goto bad; 94037737Smckusick vput(ITOV(dp)); 9419167Ssam /* 94210051Ssam * Adjust the link count of the target to 94310051Ssam * reflect the dirrewrite above. If this is 94410051Ssam * a directory it is empty and there are 94510051Ssam * no links to it, so we can squash the inode and 94610051Ssam * any space associated with it. We disallowed 94710051Ssam * renaming over top of a directory with links to 94816776Smckusick * it above, as the remaining link would point to 94916776Smckusick * a directory without "." or ".." entries. 9509167Ssam */ 95110051Ssam xp->i_nlink--; 9529167Ssam if (doingdirectory) { 95310051Ssam if (--xp->i_nlink != 0) 95410051Ssam panic("rename: linked directory"); 95539674Smckusick error = itrunc(xp, (u_long)0, IO_SYNC); 95610051Ssam } 9579167Ssam xp->i_flag |= ICHG; 95838398Smckusick iput(xp); 95910246Ssam xp = NULL; 9609167Ssam } 9619167Ssam 9629167Ssam /* 9639167Ssam * 3) Unlink the source. 9649167Ssam */ 96537737Smckusick fndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 96637737Smckusick (void)namei(fndp); 96737737Smckusick if (fndp->ni_vp != NULL) { 96837737Smckusick xp = VTOI(fndp->ni_vp); 96937737Smckusick dp = VTOI(fndp->ni_dvp); 97037737Smckusick } else { 97138069Smckusick if (fndp->ni_dvp != NULL) 97238069Smckusick vput(fndp->ni_dvp); 97337737Smckusick xp = NULL; 97417758Smckusick dp = NULL; 97537737Smckusick } 9769167Ssam /* 97737737Smckusick * Ensure that the directory entry still exists and has not 97816776Smckusick * changed while the new name has been entered. If the source is 97916776Smckusick * a file then the entry may have been unlinked or renamed. In 98016776Smckusick * either case there is no further work to be done. If the source 98116776Smckusick * is a directory then it cannot have been rmdir'ed; its link 98216776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 98337737Smckusick * The IRENAME flag ensures that it cannot be moved by another 98416776Smckusick * rename. 9859167Ssam */ 98617758Smckusick if (xp != ip) { 98716776Smckusick if (doingdirectory) 98817758Smckusick panic("rename: lost dir entry"); 98916776Smckusick } else { 9909167Ssam /* 99116776Smckusick * If the source is a directory with a 99216776Smckusick * new parent, the link count of the old 99316776Smckusick * parent directory must be decremented 99416776Smckusick * and ".." set to point to the new parent. 9959167Ssam */ 99616776Smckusick if (doingdirectory && newparent) { 9979167Ssam dp->i_nlink--; 9989167Ssam dp->i_flag |= ICHG; 99939597Smckusick error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, 100037737Smckusick sizeof (struct dirtemplate), (off_t)0, 100139597Smckusick UIO_SYSSPACE, IO_NODELOCKED, 100239597Smckusick tndp->ni_cred, (int *)0); 100316776Smckusick if (error == 0) { 100416776Smckusick if (dirbuf.dotdot_namlen != 2 || 100516776Smckusick dirbuf.dotdot_name[0] != '.' || 100616776Smckusick dirbuf.dotdot_name[1] != '.') { 100739610Smckusick dirbad(xp, 12, "rename: mangled dir"); 100816776Smckusick } else { 100916776Smckusick dirbuf.dotdot_ino = newparent; 101039597Smckusick (void) vn_rdwr(UIO_WRITE, ITOV(xp), 101116776Smckusick (caddr_t)&dirbuf, 101216776Smckusick sizeof (struct dirtemplate), 101337740Smckusick (off_t)0, UIO_SYSSPACE, 101439597Smckusick IO_NODELOCKED|IO_SYNC, 101537737Smckusick tndp->ni_cred, (int *)0); 101637737Smckusick cache_purge(ITOV(dp)); 101716776Smckusick } 101816776Smckusick } 10199167Ssam } 102037737Smckusick error = dirremove(fndp); 102137737Smckusick if (!error) { 102216776Smckusick xp->i_nlink--; 102316776Smckusick xp->i_flag |= ICHG; 10249167Ssam } 102516776Smckusick xp->i_flag &= ~IRENAME; 10269167Ssam } 10279167Ssam if (dp) 102837737Smckusick vput(ITOV(dp)); 102916776Smckusick if (xp) 103037737Smckusick vput(ITOV(xp)); 103137737Smckusick vrele(ITOV(ip)); 103237737Smckusick return (error); 10339167Ssam 10349167Ssam bad: 10359167Ssam if (xp) 103637737Smckusick vput(ITOV(xp)); 103737737Smckusick vput(ITOV(dp)); 10389167Ssam out: 10399167Ssam ip->i_nlink--; 10409167Ssam ip->i_flag |= ICHG; 104137737Smckusick vrele(ITOV(ip)); 104237737Smckusick return (error); 10437701Ssam } 10447701Ssam 10457535Sroot /* 104612756Ssam * A virgin directory (no blushing please). 104712756Ssam */ 104812756Ssam struct dirtemplate mastertemplate = { 104912756Ssam 0, 12, 1, ".", 105012756Ssam 0, DIRBLKSIZ - 12, 2, ".." 105112756Ssam }; 105212756Ssam 105312756Ssam /* 105412756Ssam * Mkdir system call 105512756Ssam */ 105637737Smckusick ufs_mkdir(ndp, vap) 105737737Smckusick struct nameidata *ndp; 105837737Smckusick struct vattr *vap; 105912756Ssam { 106012756Ssam register struct inode *ip, *dp; 106137737Smckusick struct inode *tip; 106237737Smckusick struct vnode *dvp; 106312756Ssam struct dirtemplate dirtemplate; 106437737Smckusick int error; 106537737Smckusick int dmode; 106612756Ssam 106737737Smckusick dvp = ndp->ni_dvp; 106837737Smckusick dp = VTOI(dvp); 106937737Smckusick dmode = vap->va_mode&0777; 107037737Smckusick dmode |= IFDIR; 107112756Ssam /* 107212756Ssam * Must simulate part of maknode here 107312756Ssam * in order to acquire the inode, but 107412756Ssam * not have it entered in the parent 107512756Ssam * directory. The entry is made later 107612756Ssam * after writing "." and ".." entries out. 107712756Ssam */ 107837737Smckusick error = ialloc(dp, dirpref(dp->i_fs), dmode, &tip); 107937737Smckusick if (error) { 108012756Ssam iput(dp); 108137737Smckusick return (error); 108212756Ssam } 108337737Smckusick ip = tip; 108412756Ssam #ifdef QUOTA 108512756Ssam if (ip->i_dquot != NODQUOT) 108612756Ssam panic("mkdir: dquot"); 108712756Ssam #endif 108812756Ssam ip->i_flag |= IACC|IUPD|ICHG; 108937737Smckusick ip->i_mode = dmode; 109037737Smckusick ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ 109112756Ssam ip->i_nlink = 2; 109237737Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 109312756Ssam ip->i_gid = dp->i_gid; 109412756Ssam #ifdef QUOTA 109512756Ssam ip->i_dquot = inoquota(ip); 109612756Ssam #endif 109737737Smckusick error = iupdat(ip, &time, &time, 1); 109812756Ssam 109912756Ssam /* 110012756Ssam * Bump link count in parent directory 110112756Ssam * to reflect work done below. Should 110212756Ssam * be done before reference is created 110312756Ssam * so reparation is possible if we crash. 110412756Ssam */ 110512756Ssam dp->i_nlink++; 110612756Ssam dp->i_flag |= ICHG; 110737737Smckusick error = iupdat(dp, &time, &time, 1); 110812756Ssam 110912756Ssam /* 111012756Ssam * Initialize directory with "." 111112756Ssam * and ".." from static template. 111212756Ssam */ 111312756Ssam dirtemplate = mastertemplate; 111412756Ssam dirtemplate.dot_ino = ip->i_number; 111512756Ssam dirtemplate.dotdot_ino = dp->i_number; 111639597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, 111737737Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 111839597Smckusick IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0); 111937737Smckusick if (error) { 112012756Ssam dp->i_nlink--; 112112756Ssam dp->i_flag |= ICHG; 112212756Ssam goto bad; 112312756Ssam } 112437737Smckusick if (DIRBLKSIZ > dp->i_fs->fs_fsize) 112537737Smckusick panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ 112618103Smckusick else 112718103Smckusick ip->i_size = DIRBLKSIZ; 112812756Ssam /* 112912756Ssam * Directory all set up, now 113012756Ssam * install the entry for it in 113112756Ssam * the parent directory. 113212756Ssam */ 113337737Smckusick error = direnter(ip, ndp); 113412756Ssam dp = NULL; 113537737Smckusick if (error) { 113616694Smckusick ndp->ni_nameiop = LOOKUP | NOCACHE; 113737737Smckusick error = namei(ndp); 113837737Smckusick if (!error) { 113937737Smckusick dp = VTOI(ndp->ni_vp); 114012756Ssam dp->i_nlink--; 114112756Ssam dp->i_flag |= ICHG; 114212756Ssam } 114312756Ssam } 114412756Ssam bad: 114512756Ssam /* 114612756Ssam * No need to do an explicit itrunc here, 114737737Smckusick * vrele will do this for us because we set 114812756Ssam * the link count to 0. 114912756Ssam */ 115037737Smckusick if (error) { 115112756Ssam ip->i_nlink = 0; 115212756Ssam ip->i_flag |= ICHG; 115338144Smckusick iput(ip); 115438144Smckusick } else 115538144Smckusick ndp->ni_vp = ITOV(ip); 115612756Ssam if (dp) 115712756Ssam iput(dp); 115837737Smckusick return (error); 115912756Ssam } 116012756Ssam 116112756Ssam /* 116212756Ssam * Rmdir system call. 116312756Ssam */ 116437737Smckusick ufs_rmdir(ndp) 116537737Smckusick register struct nameidata *ndp; 116612756Ssam { 116712756Ssam register struct inode *ip, *dp; 116837737Smckusick int error = 0; 116912756Ssam 117037737Smckusick ip = VTOI(ndp->ni_vp); 117137737Smckusick dp = VTOI(ndp->ni_dvp); 117212756Ssam /* 117312756Ssam * No rmdir "." please. 117412756Ssam */ 117512756Ssam if (dp == ip) { 117637737Smckusick vrele(ITOV(dp)); 117712756Ssam iput(ip); 117837737Smckusick return (EINVAL); 117912756Ssam } 118012756Ssam /* 118112756Ssam * Verify the directory is empty (and valid). 118212756Ssam * (Rmdir ".." won't be valid since 118312756Ssam * ".." will contain a reference to 118412756Ssam * the current directory and thus be 118512756Ssam * non-empty.) 118612756Ssam */ 118737737Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { 118837737Smckusick error = ENOTEMPTY; 118912756Ssam goto out; 119012756Ssam } 119112756Ssam /* 119212756Ssam * Delete reference to directory before purging 119312756Ssam * inode. If we crash in between, the directory 119412756Ssam * will be reattached to lost+found, 119512756Ssam */ 119637737Smckusick if (error = dirremove(ndp)) 119712756Ssam goto out; 119812756Ssam dp->i_nlink--; 119912756Ssam dp->i_flag |= ICHG; 120037737Smckusick cache_purge(ITOV(dp)); 120112756Ssam iput(dp); 120237737Smckusick ndp->ni_dvp = NULL; 120312756Ssam /* 120412756Ssam * Truncate inode. The only stuff left 120512756Ssam * in the directory is "." and "..". The 120612756Ssam * "." reference is inconsequential since 120712756Ssam * we're quashing it. The ".." reference 120812756Ssam * has already been adjusted above. We've 120912756Ssam * removed the "." reference and the reference 121012756Ssam * in the parent directory, but there may be 121112756Ssam * other hard links so decrement by 2 and 121212756Ssam * worry about them later. 121312756Ssam */ 121412756Ssam ip->i_nlink -= 2; 121539674Smckusick error = itrunc(ip, (u_long)0, IO_SYNC); 121637737Smckusick cache_purge(ITOV(ip)); 121712756Ssam out: 121837737Smckusick if (ndp->ni_dvp) 121912756Ssam iput(dp); 122012756Ssam iput(ip); 122137737Smckusick return (error); 122212756Ssam } 122312756Ssam 122437737Smckusick /* 122537737Smckusick * symlink -- make a symbolic link 122637737Smckusick */ 122737737Smckusick ufs_symlink(ndp, vap, target) 122837737Smckusick struct nameidata *ndp; 122937737Smckusick struct vattr *vap; 123037737Smckusick char *target; 123112756Ssam { 123237737Smckusick struct inode *ip; 123337737Smckusick int error; 123412756Ssam 123537737Smckusick error = maknode(IFLNK | vap->va_mode, ndp, &ip); 123637737Smckusick if (error) 123737737Smckusick return (error); 123839597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, 123939597Smckusick UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0); 124037737Smckusick iput(ip); 124137737Smckusick return (error); 124237737Smckusick } 124337737Smckusick 124437737Smckusick /* 124537737Smckusick * Vnode op for read and write 124637737Smckusick */ 124740345Smckusick ufs_readdir(vp, uio, cred, eofflagp) 124837737Smckusick struct vnode *vp; 124937737Smckusick register struct uio *uio; 125037737Smckusick struct ucred *cred; 125140345Smckusick int *eofflagp; 125237737Smckusick { 125339597Smckusick int count, lost, error; 125437737Smckusick 125537737Smckusick count = uio->uio_resid; 125637737Smckusick count &= ~(DIRBLKSIZ - 1); 125739597Smckusick lost = uio->uio_resid - count; 125839597Smckusick if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) 125937737Smckusick return (EINVAL); 126037737Smckusick uio->uio_resid = count; 126137737Smckusick uio->uio_iov->iov_len = count; 126239597Smckusick error = ufs_read(vp, uio, 0, cred); 126339597Smckusick uio->uio_resid += lost; 126440345Smckusick if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) 126540345Smckusick *eofflagp = 1; 126640345Smckusick else 126740345Smckusick *eofflagp = 0; 126837737Smckusick return (error); 126937737Smckusick } 127037737Smckusick 127137737Smckusick /* 127237737Smckusick * Return target name of a symbolic link 127337737Smckusick */ 127437737Smckusick ufs_readlink(vp, uiop, cred) 127537737Smckusick struct vnode *vp; 127637737Smckusick struct uio *uiop; 127737737Smckusick struct ucred *cred; 127837737Smckusick { 127937737Smckusick 128039597Smckusick return (ufs_read(vp, uiop, 0, cred)); 128137737Smckusick } 128237737Smckusick 128337737Smckusick /* 128437737Smckusick * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 128537737Smckusick * done. Iff ni_vp/ni_dvp not null and locked, unlock. 128637737Smckusick */ 128737737Smckusick ufs_abortop(ndp) 128837737Smckusick register struct nameidata *ndp; 128937737Smckusick { 129037737Smckusick 129140107Smckusick if (ndp->ni_dvp) { 129240107Smckusick if (VOP_ISLOCKED(ndp->ni_dvp)) 129340107Smckusick VOP_UNLOCK(ndp->ni_dvp); 129440107Smckusick vrele(ndp->ni_dvp); 129540107Smckusick } 129637737Smckusick if (ndp->ni_vp) { 129740107Smckusick if (VOP_ISLOCKED(ndp->ni_vp)) 129840107Smckusick VOP_UNLOCK(ndp->ni_vp); 129937737Smckusick vrele(ndp->ni_vp); 130012756Ssam } 130137737Smckusick return; 130212756Ssam } 130312756Ssam 130439909Smckusick /* 130539909Smckusick * Lock an inode. 130639909Smckusick */ 130737737Smckusick ufs_lock(vp) 130837737Smckusick struct vnode *vp; 130937737Smckusick { 131037737Smckusick register struct inode *ip = VTOI(vp); 131137737Smckusick 131237737Smckusick ILOCK(ip); 131337737Smckusick return (0); 131437737Smckusick } 131537737Smckusick 131639909Smckusick /* 131739909Smckusick * Unlock an inode. 131839909Smckusick */ 131937737Smckusick ufs_unlock(vp) 132037737Smckusick struct vnode *vp; 132137737Smckusick { 132237737Smckusick register struct inode *ip = VTOI(vp); 132337737Smckusick 132437737Smckusick if (!(ip->i_flag & ILOCKED)) 132537737Smckusick panic("ufs_unlock NOT LOCKED"); 132637737Smckusick IUNLOCK(ip); 132737737Smckusick return (0); 132837737Smckusick } 132937737Smckusick 133012756Ssam /* 133139909Smckusick * Check for a locked inode. 133239909Smckusick */ 133339909Smckusick ufs_islocked(vp) 133439909Smckusick struct vnode *vp; 133539909Smckusick { 133639909Smckusick 133739909Smckusick if (VTOI(vp)->i_flag & ILOCKED) 133839909Smckusick return (1); 133939909Smckusick return (0); 134039909Smckusick } 134139909Smckusick 134239909Smckusick /* 134337737Smckusick * Get access to bmap 134412756Ssam */ 134537737Smckusick ufs_bmap(vp, bn, vpp, bnp) 134637737Smckusick struct vnode *vp; 134737737Smckusick daddr_t bn; 134837737Smckusick struct vnode **vpp; 134937737Smckusick daddr_t *bnp; 135012756Ssam { 135137737Smckusick struct inode *ip = VTOI(vp); 135212756Ssam 135337737Smckusick if (vpp != NULL) 135437737Smckusick *vpp = ip->i_devvp; 135537737Smckusick if (bnp == NULL) 135637737Smckusick return (0); 135737737Smckusick return (bmap(ip, bn, bnp, (daddr_t *)0, (int *)0)); 135812756Ssam } 135937737Smckusick 136037737Smckusick /* 136137737Smckusick * Just call the device strategy routine 136237737Smckusick */ 136339674Smckusick int checkoverlap = 1; 136439674Smckusick 136537737Smckusick ufs_strategy(bp) 136637737Smckusick register struct buf *bp; 136737737Smckusick { 136839674Smckusick register struct inode *ip = VTOI(bp->b_vp); 136939674Smckusick register struct buf *ep; 137039674Smckusick struct vnode *vp; 137139674Smckusick struct buf *ebp; 137239674Smckusick daddr_t start, last; 137339674Smckusick int error; 137439674Smckusick 137539674Smckusick if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 137639674Smckusick panic("ufs_strategy: spec"); 137739674Smckusick if (bp->b_blkno == bp->b_lblkno) { 137839674Smckusick if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno)) 137939674Smckusick return (error); 138039896Smckusick if ((long)bp->b_blkno == -1) 138139674Smckusick clrbuf(bp); 138239674Smckusick } 138339896Smckusick if ((long)bp->b_blkno == -1) { 138439896Smckusick biodone(bp); 138539674Smckusick return (0); 138639896Smckusick } 138739674Smckusick if (checkoverlap) { 138839674Smckusick ebp = &buf[nbuf]; 138939674Smckusick start = bp->b_blkno; 139039674Smckusick last = start + btodb(bp->b_bcount) - 1; 139139674Smckusick for (ep = buf; ep < ebp; ep++) { 139239674Smckusick if (ep == bp || (ep->b_flags & B_INVAL) || 139339674Smckusick ep->b_vp == (struct vnode *)0) 139439674Smckusick continue; 139539674Smckusick if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0)) 139639674Smckusick continue; 139739674Smckusick if (vp != ip->i_devvp) 139839674Smckusick continue; 139939674Smckusick /* look for overlap */ 140039674Smckusick if (ep->b_bcount == 0 || ep->b_blkno > last || 140139674Smckusick ep->b_blkno + btodb(ep->b_bcount) <= start) 140239674Smckusick continue; 140339896Smckusick vprint("Disk overlap", vp); 140439896Smckusick printf("\tstart %d, end %d overlap start %d, end %d\n", 140539896Smckusick start, last, ep->b_blkno, 140639896Smckusick ep->b_blkno + btodb(ep->b_bcount) - 1); 140739674Smckusick } 140839674Smckusick } 140939674Smckusick vp = ip->i_devvp; 141039674Smckusick bp->b_dev = vp->v_rdev; 141139674Smckusick (*(vp->v_op->vn_strategy))(bp); 141237737Smckusick return (0); 141337737Smckusick } 141437737Smckusick 141537737Smckusick /* 141639674Smckusick * Print out the contents of an inode. 141739674Smckusick */ 141839674Smckusick ufs_print(vp) 141939674Smckusick struct vnode *vp; 142039674Smckusick { 142139674Smckusick register struct inode *ip = VTOI(vp); 142239674Smckusick 142340293Smckusick printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number, 142440293Smckusick major(ip->i_dev), minor(ip->i_dev)); 142540293Smckusick #ifdef FIFO 142640293Smckusick if (vp->v_type == VFIFO) 142740293Smckusick fifo_printinfo(vp); 142840293Smckusick #endif /* FIFO */ 142940293Smckusick printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : ""); 143039900Smckusick if (ip->i_spare0 == 0) 143139900Smckusick return; 143239900Smckusick printf("\towner pid %d", ip->i_spare0); 143339900Smckusick if (ip->i_spare1) 143439900Smckusick printf(" waiting pid %d", ip->i_spare1); 143539900Smckusick printf("\n"); 143639674Smckusick } 143739674Smckusick 143839674Smckusick /* 143939628Smckusick * Read wrapper for special devices. 144039628Smckusick */ 144139628Smckusick ufsspec_read(vp, uio, ioflag, cred) 144239628Smckusick struct vnode *vp; 144339628Smckusick struct uio *uio; 144439628Smckusick int ioflag; 144539628Smckusick struct ucred *cred; 144639628Smckusick { 144739628Smckusick 144839628Smckusick /* 144939628Smckusick * Set access flag. 145039628Smckusick */ 145139628Smckusick VTOI(vp)->i_flag |= IACC; 145239628Smckusick return (spec_read(vp, uio, ioflag, cred)); 145339628Smckusick } 145439628Smckusick 145539628Smckusick /* 145639628Smckusick * Write wrapper for special devices. 145739628Smckusick */ 145839628Smckusick ufsspec_write(vp, uio, ioflag, cred) 145939628Smckusick struct vnode *vp; 146039628Smckusick struct uio *uio; 146139628Smckusick int ioflag; 146239628Smckusick struct ucred *cred; 146339628Smckusick { 146439628Smckusick 146539628Smckusick /* 146639628Smckusick * Set update and change flags. 146739628Smckusick */ 146839628Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 146939628Smckusick return (spec_write(vp, uio, ioflag, cred)); 147039628Smckusick } 147139628Smckusick 147239628Smckusick /* 147339628Smckusick * Close wrapper for special devices. 147439628Smckusick * 147539628Smckusick * Update the times on the inode then do device close. 147639628Smckusick */ 147739628Smckusick ufsspec_close(vp, fflag, cred) 147839628Smckusick struct vnode *vp; 147939628Smckusick int fflag; 148039628Smckusick struct ucred *cred; 148139628Smckusick { 148239628Smckusick register struct inode *ip = VTOI(vp); 148339628Smckusick 148439815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 148539628Smckusick ITIMES(ip, &time, &time); 148639628Smckusick return (spec_close(vp, fflag, cred)); 148739628Smckusick } 148839628Smckusick 148940290Smckusick #ifdef FIFO 149039628Smckusick /* 149140290Smckusick * Read wrapper for fifo's 149240290Smckusick */ 149340290Smckusick ufsfifo_read(vp, uio, ioflag, cred) 149440290Smckusick struct vnode *vp; 149540290Smckusick struct uio *uio; 149640290Smckusick int ioflag; 149740290Smckusick struct ucred *cred; 149840290Smckusick { 149940290Smckusick 150040290Smckusick /* 150140290Smckusick * Set access flag. 150240290Smckusick */ 150340290Smckusick VTOI(vp)->i_flag |= IACC; 150440290Smckusick return (fifo_read(vp, uio, ioflag, cred)); 150540290Smckusick } 150640290Smckusick 150740290Smckusick /* 150840290Smckusick * Write wrapper for fifo's. 150940290Smckusick */ 151040290Smckusick ufsfifo_write(vp, uio, ioflag, cred) 151140290Smckusick struct vnode *vp; 151240290Smckusick struct uio *uio; 151340290Smckusick int ioflag; 151440290Smckusick struct ucred *cred; 151540290Smckusick { 151640290Smckusick 151740290Smckusick /* 151840290Smckusick * Set update and change flags. 151940290Smckusick */ 152040290Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 152140290Smckusick return (fifo_write(vp, uio, ioflag, cred)); 152240290Smckusick } 152340290Smckusick 152440290Smckusick /* 152540290Smckusick * Close wrapper for fifo's. 152640290Smckusick * 152740290Smckusick * Update the times on the inode then do device close. 152840290Smckusick */ 152940290Smckusick ufsfifo_close(vp, fflag, cred) 153040290Smckusick struct vnode *vp; 153140290Smckusick int fflag; 153240290Smckusick struct ucred *cred; 153340290Smckusick { 153440290Smckusick register struct inode *ip = VTOI(vp); 153540290Smckusick 153640290Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 153740290Smckusick ITIMES(ip, &time, &time); 153840290Smckusick return (fifo_close(vp, fflag, cred)); 153940290Smckusick } 154040290Smckusick #endif /* FIFO */ 154140290Smckusick 154240290Smckusick /* 154337737Smckusick * Make a new file. 154437737Smckusick */ 154537737Smckusick maknode(mode, ndp, ipp) 154637737Smckusick int mode; 154737737Smckusick register struct nameidata *ndp; 154837737Smckusick struct inode **ipp; 154937737Smckusick { 155037737Smckusick register struct inode *ip; 155137737Smckusick struct inode *tip; 155237737Smckusick register struct inode *pdir = VTOI(ndp->ni_dvp); 155337737Smckusick ino_t ipref; 155437737Smckusick int error; 155537737Smckusick 155637737Smckusick *ipp = 0; 155737737Smckusick if ((mode & IFMT) == IFDIR) 155837737Smckusick ipref = dirpref(pdir->i_fs); 155937737Smckusick else 156037737Smckusick ipref = pdir->i_number; 156137737Smckusick error = ialloc(pdir, ipref, mode, &tip); 156237737Smckusick if (error) { 156337737Smckusick iput(pdir); 156437737Smckusick return (error); 156537737Smckusick } 156637737Smckusick ip = tip; 156737737Smckusick #ifdef QUOTA 156837737Smckusick if (ip->i_dquot != NODQUOT) 156937737Smckusick panic("maknode: dquot"); 157037737Smckusick #endif 157137737Smckusick ip->i_flag |= IACC|IUPD|ICHG; 157237737Smckusick if ((mode & IFMT) == 0) 157337737Smckusick mode |= IFREG; 157437737Smckusick ip->i_mode = mode; 157537737Smckusick ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ 157637737Smckusick ip->i_nlink = 1; 157737737Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 157837737Smckusick ip->i_gid = pdir->i_gid; 157937737Smckusick if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && 158037737Smckusick suser(ndp->ni_cred, NULL)) 158137737Smckusick ip->i_mode &= ~ISGID; 158237737Smckusick #ifdef QUOTA 158337737Smckusick ip->i_dquot = inoquota(ip); 158437737Smckusick #endif 158537737Smckusick 158637737Smckusick /* 158737737Smckusick * Make sure inode goes to disk before directory entry. 158837737Smckusick */ 158937737Smckusick if ((error = iupdat(ip, &time, &time, 1)) || 159037737Smckusick (error = direnter(ip, ndp))) { 159137737Smckusick /* 159237737Smckusick * Write error occurred trying to update the inode 159337737Smckusick * or the directory so must deallocate the inode. 159437737Smckusick */ 159537737Smckusick ip->i_nlink = 0; 159637737Smckusick ip->i_flag |= ICHG; 159737737Smckusick iput(ip); 159837737Smckusick return (error); 159937737Smckusick } 160037737Smckusick *ipp = ip; 160137737Smckusick return (0); 160237737Smckusick } 1603