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*49762Smckusick * @(#)lfs_vnops.c 7.64 (Berkeley) 05/16/91 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 1247571Skarels #include "namei.h" 1347571Skarels #include "resourcevar.h" 1417101Sbloom #include "kernel.h" 1517101Sbloom #include "file.h" 1617101Sbloom #include "stat.h" 1717101Sbloom #include "buf.h" 1817101Sbloom #include "proc.h" 1937737Smckusick #include "conf.h" 2017101Sbloom #include "mount.h" 2137737Smckusick #include "vnode.h" 2240653Smckusick #include "specdev.h" 2348039Smckusick #include "fifo.h" 2446207Smckusick #include "malloc.h" 2537Sbill 2647571Skarels #include "lockf.h" 2747571Skarels #include "quota.h" 2847571Skarels #include "inode.h" 2949737Smckusick #include "dir.h" 3047571Skarels #include "fs.h" 3147571Skarels 329167Ssam /* 3337737Smckusick * Create a regular file 349167Ssam */ 3548039Smckusick ufs_create(ndp, vap, p) 3637737Smckusick struct nameidata *ndp; 3737737Smckusick struct vattr *vap; 3848039Smckusick struct proc *p; 396254Sroot { 4037737Smckusick struct inode *ip; 4137737Smckusick int error; 426254Sroot 4337737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 4437737Smckusick return (error); 4537737Smckusick ndp->ni_vp = ITOV(ip); 4637737Smckusick return (0); 476254Sroot } 486254Sroot 4937Sbill /* 5037737Smckusick * Mknod vnode call 516254Sroot */ 5237737Smckusick /* ARGSUSED */ 5348039Smckusick ufs_mknod(ndp, vap, cred, p) 5437737Smckusick struct nameidata *ndp; 5537737Smckusick struct ucred *cred; 5637737Smckusick struct vattr *vap; 5748039Smckusick struct proc *p; 586254Sroot { 5939435Smckusick register struct vnode *vp; 6037737Smckusick struct inode *ip; 6137737Smckusick int error; 626254Sroot 6337737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 6437737Smckusick return (error); 6540290Smckusick ip->i_flag |= IACC|IUPD|ICHG; 6640290Smckusick if (vap->va_rdev != VNOVAL) { 6737737Smckusick /* 6837737Smckusick * Want to be able to use this to make badblock 6937737Smckusick * inodes, so don't truncate the dev number. 7037737Smckusick */ 7139608Smckusick ip->i_rdev = vap->va_rdev; 7212756Ssam } 7337737Smckusick /* 7437737Smckusick * Remove inode so that it will be reloaded by iget and 7537737Smckusick * checked to see if it is an alias of an existing entry 7637737Smckusick * in the inode cache. 7737737Smckusick */ 7840290Smckusick vp = ITOV(ip); 7940290Smckusick vput(vp); 8039435Smckusick vp->v_type = VNON; 8139435Smckusick vgone(vp); 8237737Smckusick return (0); 836254Sroot } 846254Sroot 856254Sroot /* 8637737Smckusick * Open called. 8737737Smckusick * 8837737Smckusick * Nothing to do. 896254Sroot */ 9037737Smckusick /* ARGSUSED */ 9148039Smckusick ufs_open(vp, mode, cred, p) 9237737Smckusick struct vnode *vp; 9337737Smckusick int mode; 9437737Smckusick struct ucred *cred; 9548039Smckusick struct proc *p; 966254Sroot { 976254Sroot 9837737Smckusick return (0); 996254Sroot } 1006254Sroot 1016254Sroot /* 10237737Smckusick * Close called 10337737Smckusick * 10437737Smckusick * Update the times on the inode. 1056254Sroot */ 10637737Smckusick /* ARGSUSED */ 10748039Smckusick ufs_close(vp, fflag, cred, p) 10837737Smckusick struct vnode *vp; 10937737Smckusick int fflag; 11037737Smckusick struct ucred *cred; 11148039Smckusick struct proc *p; 1126254Sroot { 11337737Smckusick register struct inode *ip = VTOI(vp); 1146254Sroot 11539815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 11637737Smckusick ITIMES(ip, &time, &time); 11737737Smckusick return (0); 1186254Sroot } 1196254Sroot 12041312Smckusick /* 12141312Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 12241312Smckusick * The mode is shifted to select the owner/group/other fields. The 12341312Smckusick * super user is granted all permissions. 12441312Smckusick */ 12548039Smckusick ufs_access(vp, mode, cred, p) 12637737Smckusick struct vnode *vp; 12741312Smckusick register int mode; 12837737Smckusick struct ucred *cred; 12948039Smckusick struct proc *p; 1306254Sroot { 13141312Smckusick register struct inode *ip = VTOI(vp); 13241312Smckusick register gid_t *gp; 13341312Smckusick int i, error; 1346254Sroot 13541312Smckusick #ifdef DIAGNOSTIC 13641312Smckusick if (!VOP_ISLOCKED(vp)) { 13741312Smckusick vprint("ufs_access: not locked", vp); 13841312Smckusick panic("ufs_access: not locked"); 13941312Smckusick } 14041312Smckusick #endif 14141312Smckusick #ifdef QUOTA 14241312Smckusick if (mode & VWRITE) { 14341312Smckusick switch (vp->v_type) { 14441312Smckusick case VREG: case VDIR: case VLNK: 14541312Smckusick if (error = getinoquota(ip)) 14641312Smckusick return (error); 14741312Smckusick } 14841312Smckusick } 14941312Smckusick #endif /* QUOTA */ 15041312Smckusick /* 15141312Smckusick * If you're the super-user, you always get access. 15241312Smckusick */ 15341312Smckusick if (cred->cr_uid == 0) 15441312Smckusick return (0); 15541312Smckusick /* 15641312Smckusick * Access check is based on only one of owner, group, public. 15741312Smckusick * If not owner, then check group. If not a member of the 15841312Smckusick * group, then check public access. 15941312Smckusick */ 16041312Smckusick if (cred->cr_uid != ip->i_uid) { 16141312Smckusick mode >>= 3; 16241312Smckusick gp = cred->cr_groups; 16341312Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 16441312Smckusick if (ip->i_gid == *gp) 16541312Smckusick goto found; 16641312Smckusick mode >>= 3; 16741312Smckusick found: 16841312Smckusick ; 16941312Smckusick } 17041312Smckusick if ((ip->i_mode & mode) != 0) 17141312Smckusick return (0); 17241312Smckusick return (EACCES); 1736254Sroot } 1746254Sroot 17537737Smckusick /* ARGSUSED */ 17648039Smckusick ufs_getattr(vp, vap, cred, p) 17737737Smckusick struct vnode *vp; 17837737Smckusick register struct vattr *vap; 17937737Smckusick struct ucred *cred; 18048039Smckusick struct proc *p; 1816254Sroot { 18237737Smckusick register struct inode *ip = VTOI(vp); 1836254Sroot 18437737Smckusick ITIMES(ip, &time, &time); 1856254Sroot /* 18637737Smckusick * Copy from inode table 1876254Sroot */ 18837737Smckusick vap->va_fsid = ip->i_dev; 18937737Smckusick vap->va_fileid = ip->i_number; 19037737Smckusick vap->va_mode = ip->i_mode & ~IFMT; 19137737Smckusick vap->va_nlink = ip->i_nlink; 19237737Smckusick vap->va_uid = ip->i_uid; 19337737Smckusick vap->va_gid = ip->i_gid; 19437737Smckusick vap->va_rdev = (dev_t)ip->i_rdev; 19541312Smckusick #ifdef tahoe 19641312Smckusick vap->va_size = ip->i_size; 19741312Smckusick vap->va_size_rsv = 0; 19841312Smckusick #else 19940641Smckusick vap->va_qsize = ip->i_din.di_qsize; 20041312Smckusick #endif 20137737Smckusick vap->va_atime.tv_sec = ip->i_atime; 20238578Smckusick vap->va_atime.tv_usec = 0; 20337737Smckusick vap->va_mtime.tv_sec = ip->i_mtime; 20438578Smckusick vap->va_mtime.tv_usec = 0; 20537737Smckusick vap->va_ctime.tv_sec = ip->i_ctime; 20638578Smckusick vap->va_ctime.tv_usec = 0; 20738254Smckusick vap->va_flags = ip->i_flags; 20838254Smckusick vap->va_gen = ip->i_gen; 20937737Smckusick /* this doesn't belong here */ 21037737Smckusick if (vp->v_type == VBLK) 21137737Smckusick vap->va_blocksize = BLKDEV_IOSIZE; 21237737Smckusick else if (vp->v_type == VCHR) 21337737Smckusick vap->va_blocksize = MAXBSIZE; 2147142Smckusick else 21537737Smckusick vap->va_blocksize = ip->i_fs->fs_bsize; 21638657Smckusick vap->va_bytes = dbtob(ip->i_blocks); 21740641Smckusick vap->va_bytes_rsv = 0; 21837737Smckusick vap->va_type = vp->v_type; 21937737Smckusick return (0); 2206254Sroot } 2216254Sroot 2226254Sroot /* 22337737Smckusick * Set attribute vnode op. called from several syscalls 2246254Sroot */ 22548039Smckusick ufs_setattr(vp, vap, cred, p) 22637737Smckusick register struct vnode *vp; 22737737Smckusick register struct vattr *vap; 22837737Smckusick register struct ucred *cred; 22948039Smckusick struct proc *p; 2306254Sroot { 23137737Smckusick register struct inode *ip = VTOI(vp); 23237737Smckusick int error = 0; 2336254Sroot 23437737Smckusick /* 23537737Smckusick * Check for unsetable attributes. 23637737Smckusick */ 23737737Smckusick if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 23837737Smckusick (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 23937737Smckusick (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 24038254Smckusick ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 24137737Smckusick return (EINVAL); 24216540Ssam } 24337737Smckusick /* 24437737Smckusick * Go through the fields and update iff not VNOVAL. 24537737Smckusick */ 24637737Smckusick if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) 24747571Skarels if (error = chown1(vp, vap->va_uid, vap->va_gid, p)) 24837737Smckusick return (error); 24937737Smckusick if (vap->va_size != VNOVAL) { 25037737Smckusick if (vp->v_type == VDIR) 25137737Smckusick return (EISDIR); 25239674Smckusick if (error = itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */ 25337737Smckusick return (error); 25413878Ssam } 25537737Smckusick if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 25637773Smckusick if (cred->cr_uid != ip->i_uid && 25747571Skarels (error = suser(cred, &p->p_acflag))) 25837773Smckusick return (error); 25937737Smckusick if (vap->va_atime.tv_sec != VNOVAL) 26037737Smckusick ip->i_flag |= IACC; 26137737Smckusick if (vap->va_mtime.tv_sec != VNOVAL) 26237737Smckusick ip->i_flag |= IUPD; 26337737Smckusick ip->i_flag |= ICHG; 26437737Smckusick if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) 26537737Smckusick return (error); 2666254Sroot } 26737737Smckusick if (vap->va_mode != (u_short)VNOVAL) 26847571Skarels error = chmod1(vp, (int)vap->va_mode, p); 26938254Smckusick if (vap->va_flags != VNOVAL) { 27038254Smckusick if (cred->cr_uid != ip->i_uid && 27147571Skarels (error = suser(cred, &p->p_acflag))) 27238254Smckusick return (error); 27338254Smckusick if (cred->cr_uid == 0) { 27438254Smckusick ip->i_flags = vap->va_flags; 27538254Smckusick } else { 27638254Smckusick ip->i_flags &= 0xffff0000; 27738254Smckusick ip->i_flags |= (vap->va_flags & 0xffff); 27838254Smckusick } 27938254Smckusick ip->i_flag |= ICHG; 28038254Smckusick } 28137737Smckusick return (error); 2826254Sroot } 2836254Sroot 2846254Sroot /* 2859167Ssam * Change the mode on a file. 2869167Ssam * Inode must be locked before calling. 2879167Ssam */ 28847571Skarels chmod1(vp, mode, p) 28937737Smckusick register struct vnode *vp; 2907701Ssam register int mode; 29147571Skarels struct proc *p; 2927701Ssam { 29347571Skarels register struct ucred *cred = p->p_ucred; 29437737Smckusick register struct inode *ip = VTOI(vp); 29537773Smckusick int error; 2967868Sroot 29737773Smckusick if (cred->cr_uid != ip->i_uid && 29847571Skarels (error = suser(cred, &p->p_acflag))) 29937773Smckusick return (error); 30037737Smckusick if (cred->cr_uid) { 30146206Smckusick if (vp->v_type != VDIR && (mode & ISVTX)) 30245783Sbostic return (EFTYPE); 30346206Smckusick if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) 30445783Sbostic return (EPERM); 3057439Sroot } 30645783Sbostic ip->i_mode &= ~07777; 30737737Smckusick ip->i_mode |= mode & 07777; 3086254Sroot ip->i_flag |= ICHG; 30937737Smckusick if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) 31045722Smckusick (void) vnode_pager_uncache(vp); 31121015Smckusick return (0); 3125992Swnj } 3135992Swnj 3149167Ssam /* 3157701Ssam * Perform chown operation on inode ip; 3167701Ssam * inode must be locked prior to call. 3177701Ssam */ 31847571Skarels chown1(vp, uid, gid, p) 31937737Smckusick register struct vnode *vp; 32037737Smckusick uid_t uid; 32137737Smckusick gid_t gid; 32247571Skarels struct proc *p; 3237701Ssam { 32437737Smckusick register struct inode *ip = VTOI(vp); 32547571Skarels register struct ucred *cred = p->p_ucred; 32641312Smckusick uid_t ouid; 32741312Smckusick gid_t ogid; 32841312Smckusick int error = 0; 3297701Ssam #ifdef QUOTA 33041312Smckusick register int i; 33141312Smckusick long change; 33211811Ssam #endif 3337701Ssam 33437737Smckusick if (uid == (u_short)VNOVAL) 33511811Ssam uid = ip->i_uid; 33637737Smckusick if (gid == (u_short)VNOVAL) 33711811Ssam gid = ip->i_gid; 33836614Sbostic /* 33936614Sbostic * If we don't own the file, are trying to change the owner 34036614Sbostic * of the file, or are not a member of the target group, 34136614Sbostic * the caller must be superuser or the call fails. 34236614Sbostic */ 34337737Smckusick if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || 34437737Smckusick !groupmember((gid_t)gid, cred)) && 34547571Skarels (error = suser(cred, &p->p_acflag))) 34637737Smckusick return (error); 34741312Smckusick ouid = ip->i_uid; 34841312Smckusick ogid = ip->i_gid; 34911811Ssam #ifdef QUOTA 35041312Smckusick if (error = getinoquota(ip)) 35141312Smckusick return (error); 35241312Smckusick if (ouid == uid) { 35341312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 35441312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 35541312Smckusick } 35641312Smckusick if (ogid == gid) { 35741312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 35841312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 35941312Smckusick } 36041312Smckusick change = ip->i_blocks; 36141312Smckusick (void) chkdq(ip, -change, cred, CHOWN); 36241312Smckusick (void) chkiq(ip, -1, cred, CHOWN); 36341312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 36441312Smckusick dqrele(vp, ip->i_dquot[i]); 36541312Smckusick ip->i_dquot[i] = NODQUOT; 36641312Smckusick } 3677482Skre #endif 36811811Ssam ip->i_uid = uid; 36911811Ssam ip->i_gid = gid; 3707701Ssam #ifdef QUOTA 37141312Smckusick if ((error = getinoquota(ip)) == 0) { 37241312Smckusick if (ouid == uid) { 37341312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 37441312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 37541312Smckusick } 37641312Smckusick if (ogid == gid) { 37741312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 37841312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 37941312Smckusick } 38041312Smckusick if ((error = chkdq(ip, change, cred, CHOWN)) == 0) { 38141312Smckusick if ((error = chkiq(ip, 1, cred, CHOWN)) == 0) 38241927Smckusick goto good; 38341312Smckusick else 38441312Smckusick (void) chkdq(ip, -change, cred, CHOWN|FORCE); 38541312Smckusick } 38641312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 38741312Smckusick dqrele(vp, ip->i_dquot[i]); 38841312Smckusick ip->i_dquot[i] = NODQUOT; 38941312Smckusick } 39041312Smckusick } 39141312Smckusick ip->i_uid = ouid; 39241312Smckusick ip->i_gid = ogid; 39341312Smckusick if (getinoquota(ip) == 0) { 39441312Smckusick if (ouid == uid) { 39541312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 39641312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 39741312Smckusick } 39841312Smckusick if (ogid == gid) { 39941312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 40041312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 40141312Smckusick } 40241927Smckusick (void) chkdq(ip, change, cred, FORCE|CHOWN); 40341927Smckusick (void) chkiq(ip, 1, cred, FORCE|CHOWN); 40442440Smckusick (void) getinoquota(ip); 40541312Smckusick } 40642440Smckusick return (error); 40741927Smckusick good: 40842440Smckusick if (getinoquota(ip)) 40942440Smckusick panic("chown: lost quota"); 41042440Smckusick #endif /* QUOTA */ 41141312Smckusick if (ouid != uid || ogid != gid) 41241312Smckusick ip->i_flag |= ICHG; 41341312Smckusick if (ouid != uid && cred->cr_uid != 0) 41441312Smckusick ip->i_mode &= ~ISUID; 41541312Smckusick if (ogid != gid && cred->cr_uid != 0) 41641312Smckusick ip->i_mode &= ~ISGID; 41712646Ssam return (0); 41837Sbill } 41937Sbill 42039608Smckusick /* 42139608Smckusick * Vnode op for reading. 42239608Smckusick */ 42337737Smckusick /* ARGSUSED */ 42439608Smckusick ufs_read(vp, uio, ioflag, cred) 42539608Smckusick struct vnode *vp; 42639608Smckusick register struct uio *uio; 42739608Smckusick int ioflag; 42839608Smckusick struct ucred *cred; 42939608Smckusick { 43039608Smckusick register struct inode *ip = VTOI(vp); 43139608Smckusick register struct fs *fs; 43239608Smckusick struct buf *bp; 43339608Smckusick daddr_t lbn, bn, rablock; 43439896Smckusick int size, diff, error = 0; 43539608Smckusick long n, on, type; 43639608Smckusick 43748039Smckusick #ifdef DIAGNOSTIC 43839608Smckusick if (uio->uio_rw != UIO_READ) 43939608Smckusick panic("ufs_read mode"); 44039608Smckusick type = ip->i_mode & IFMT; 44139608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 44239608Smckusick panic("ufs_read type"); 44348039Smckusick #endif 44439608Smckusick if (uio->uio_resid == 0) 44539608Smckusick return (0); 44639608Smckusick if (uio->uio_offset < 0) 44739608Smckusick return (EINVAL); 44839608Smckusick ip->i_flag |= IACC; 44939608Smckusick fs = ip->i_fs; 45039608Smckusick do { 45139608Smckusick lbn = lblkno(fs, uio->uio_offset); 45239608Smckusick on = blkoff(fs, uio->uio_offset); 45339608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 45439608Smckusick diff = ip->i_size - uio->uio_offset; 45539608Smckusick if (diff <= 0) 45639608Smckusick return (0); 45739608Smckusick if (diff < n) 45839608Smckusick n = diff; 45939608Smckusick size = blksize(fs, ip, lbn); 46039674Smckusick rablock = lbn + 1; 46139896Smckusick if (vp->v_lastr + 1 == lbn && 46239896Smckusick lblktosize(fs, rablock) < ip->i_size) 46339896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 46439896Smckusick blksize(fs, ip, rablock), NOCRED, &bp); 46539608Smckusick else 46639674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 46739815Smckusick vp->v_lastr = lbn; 46839608Smckusick n = MIN(n, size - bp->b_resid); 46939608Smckusick if (error) { 47039608Smckusick brelse(bp); 47139608Smckusick return (error); 47239608Smckusick } 47339608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 47439608Smckusick if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size) 47539608Smckusick bp->b_flags |= B_AGE; 47639608Smckusick brelse(bp); 47739608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 47839608Smckusick return (error); 47939608Smckusick } 48039608Smckusick 48139608Smckusick /* 48239608Smckusick * Vnode op for writing. 48339608Smckusick */ 48439608Smckusick ufs_write(vp, uio, ioflag, cred) 48539608Smckusick register struct vnode *vp; 48639608Smckusick struct uio *uio; 48739608Smckusick int ioflag; 48839608Smckusick struct ucred *cred; 48939608Smckusick { 49048039Smckusick struct proc *p = uio->uio_procp; 49139608Smckusick register struct inode *ip = VTOI(vp); 49239608Smckusick register struct fs *fs; 49339608Smckusick struct buf *bp; 49439608Smckusick daddr_t lbn, bn; 49539608Smckusick u_long osize; 49645722Smckusick int n, on, flags; 49745722Smckusick int size, resid, error = 0; 49839608Smckusick 49948039Smckusick #ifdef DIAGNOSTIC 50039608Smckusick if (uio->uio_rw != UIO_WRITE) 50139608Smckusick panic("ufs_write mode"); 50248039Smckusick #endif 50339608Smckusick switch (vp->v_type) { 50439608Smckusick case VREG: 50539608Smckusick if (ioflag & IO_APPEND) 50639608Smckusick uio->uio_offset = ip->i_size; 50739608Smckusick /* fall through */ 50839608Smckusick case VLNK: 50939608Smckusick break; 51039608Smckusick 51139608Smckusick case VDIR: 51239608Smckusick if ((ioflag & IO_SYNC) == 0) 51339608Smckusick panic("ufs_write nonsync dir write"); 51439608Smckusick break; 51539608Smckusick 51639608Smckusick default: 51739608Smckusick panic("ufs_write type"); 51839608Smckusick } 51939608Smckusick if (uio->uio_offset < 0) 52039608Smckusick return (EINVAL); 52139608Smckusick if (uio->uio_resid == 0) 52239608Smckusick return (0); 52339608Smckusick /* 52439608Smckusick * Maybe this should be above the vnode op call, but so long as 52539608Smckusick * file servers have no limits, i don't think it matters 52639608Smckusick */ 52749679Smckusick if (vp->v_type == VREG && p && 52839608Smckusick uio->uio_offset + uio->uio_resid > 52947571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 53047571Skarels psignal(p, SIGXFSZ); 53139608Smckusick return (EFBIG); 53239608Smckusick } 53339608Smckusick resid = uio->uio_resid; 53439608Smckusick osize = ip->i_size; 53539608Smckusick fs = ip->i_fs; 53639674Smckusick flags = 0; 53739674Smckusick if (ioflag & IO_SYNC) 53839674Smckusick flags = B_SYNC; 53939608Smckusick do { 54039608Smckusick lbn = lblkno(fs, uio->uio_offset); 54139608Smckusick on = blkoff(fs, uio->uio_offset); 54239608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 54339608Smckusick if (n < fs->fs_bsize) 54439674Smckusick flags |= B_CLRBUF; 54539608Smckusick else 54639674Smckusick flags &= ~B_CLRBUF; 54739674Smckusick if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) 54839608Smckusick break; 54939674Smckusick bn = bp->b_blkno; 55045722Smckusick if (uio->uio_offset + n > ip->i_size) { 55139608Smckusick ip->i_size = uio->uio_offset + n; 55245722Smckusick vnode_pager_setsize(vp, ip->i_size); 55345722Smckusick } 55439608Smckusick size = blksize(fs, ip, lbn); 55545722Smckusick (void) vnode_pager_uncache(vp); 55639608Smckusick n = MIN(n, size - bp->b_resid); 55739608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 55839608Smckusick if (ioflag & IO_SYNC) 55939608Smckusick (void) bwrite(bp); 56039608Smckusick else if (n + on == fs->fs_bsize) { 56139608Smckusick bp->b_flags |= B_AGE; 56239608Smckusick bawrite(bp); 56339608Smckusick } else 56439608Smckusick bdwrite(bp); 56539608Smckusick ip->i_flag |= IUPD|ICHG; 56639608Smckusick if (cred->cr_uid != 0) 56739608Smckusick ip->i_mode &= ~(ISUID|ISGID); 56839608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 56939608Smckusick if (error && (ioflag & IO_UNIT)) { 57039674Smckusick (void) itrunc(ip, osize, ioflag & IO_SYNC); 57139608Smckusick uio->uio_offset -= resid - uio->uio_resid; 57239608Smckusick uio->uio_resid = resid; 57339608Smckusick } 57442493Smckusick if (!error && (ioflag & IO_SYNC)) 57542493Smckusick error = iupdat(ip, &time, &time, 1); 57639608Smckusick return (error); 57739608Smckusick } 57839608Smckusick 57939608Smckusick /* ARGSUSED */ 58048039Smckusick ufs_ioctl(vp, com, data, fflag, cred, p) 58137737Smckusick struct vnode *vp; 58237737Smckusick int com; 58337737Smckusick caddr_t data; 58437737Smckusick int fflag; 58537737Smckusick struct ucred *cred; 58648039Smckusick struct proc *p; 58711811Ssam { 58811811Ssam 58937737Smckusick return (ENOTTY); 59011811Ssam } 59111811Ssam 59237737Smckusick /* ARGSUSED */ 59348039Smckusick ufs_select(vp, which, fflags, cred, p) 59437737Smckusick struct vnode *vp; 59540290Smckusick int which, fflags; 59637737Smckusick struct ucred *cred; 59748039Smckusick struct proc *p; 59837737Smckusick { 59937737Smckusick 60048039Smckusick /* 60148039Smckusick * We should really check to see if I/O is possible. 60248039Smckusick */ 60348039Smckusick return (1); 60437737Smckusick } 60537737Smckusick 6069167Ssam /* 60737737Smckusick * Mmap a file 60837737Smckusick * 60937737Smckusick * NB Currently unsupported. 6109167Ssam */ 61137737Smckusick /* ARGSUSED */ 61248039Smckusick ufs_mmap(vp, fflags, cred, p) 61337737Smckusick struct vnode *vp; 61437737Smckusick int fflags; 61537737Smckusick struct ucred *cred; 61648039Smckusick struct proc *p; 61737Sbill { 61837Sbill 61937737Smckusick return (EINVAL); 62037Sbill } 6217535Sroot 6229167Ssam /* 62337737Smckusick * Synch an open file. 6249167Ssam */ 62537737Smckusick /* ARGSUSED */ 62648039Smckusick ufs_fsync(vp, fflags, cred, waitfor, p) 62737737Smckusick struct vnode *vp; 62837737Smckusick int fflags; 62937737Smckusick struct ucred *cred; 63039597Smckusick int waitfor; 63148039Smckusick struct proc *p; 6327701Ssam { 63339597Smckusick struct inode *ip = VTOI(vp); 6347701Ssam 63548039Smckusick if (fflags & FWRITE) 63637737Smckusick ip->i_flag |= ICHG; 63739674Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 63839674Smckusick return (iupdat(ip, &time, &time, waitfor == MNT_WAIT)); 6397701Ssam } 6407701Ssam 6419167Ssam /* 64237737Smckusick * Seek on a file 64337737Smckusick * 64437737Smckusick * Nothing to do, so just return. 6459167Ssam */ 64637737Smckusick /* ARGSUSED */ 64737737Smckusick ufs_seek(vp, oldoff, newoff, cred) 64837737Smckusick struct vnode *vp; 64937737Smckusick off_t oldoff, newoff; 65037737Smckusick struct ucred *cred; 6517701Ssam { 6527701Ssam 65337737Smckusick return (0); 65437737Smckusick } 65537737Smckusick 65637737Smckusick /* 65737737Smckusick * ufs remove 65837737Smckusick * Hard to avoid races here, especially 65937737Smckusick * in unlinking directories. 66037737Smckusick */ 66148039Smckusick ufs_remove(ndp, p) 66237737Smckusick struct nameidata *ndp; 66348039Smckusick struct proc *p; 66437737Smckusick { 66537737Smckusick register struct inode *ip, *dp; 66637737Smckusick int error; 66737737Smckusick 66837737Smckusick ip = VTOI(ndp->ni_vp); 66937737Smckusick dp = VTOI(ndp->ni_dvp); 67037737Smckusick error = dirremove(ndp); 67137737Smckusick if (!error) { 67237737Smckusick ip->i_nlink--; 67337737Smckusick ip->i_flag |= ICHG; 6747701Ssam } 67537737Smckusick if (dp == ip) 67637737Smckusick vrele(ITOV(ip)); 67737737Smckusick else 67837737Smckusick iput(ip); 67937737Smckusick iput(dp); 68037737Smckusick return (error); 6817701Ssam } 6827701Ssam 6839167Ssam /* 68437737Smckusick * link vnode call 6859167Ssam */ 68648039Smckusick ufs_link(vp, ndp, p) 68737737Smckusick register struct vnode *vp; 68837737Smckusick register struct nameidata *ndp; 68948039Smckusick struct proc *p; 6909167Ssam { 69137737Smckusick register struct inode *ip = VTOI(vp); 69237737Smckusick int error; 6939167Ssam 69449737Smckusick #ifdef DIANOSTIC 69549737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 69649737Smckusick panic("ufs_link: no name"); 69749737Smckusick #endif 69849737Smckusick if ((unsigned short)ip->i_nlink >= LINK_MAX) { 69949737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 70046251Smckusick return (EMLINK); 70149737Smckusick } 70237737Smckusick if (ndp->ni_dvp != vp) 70337737Smckusick ILOCK(ip); 70437737Smckusick ip->i_nlink++; 70537737Smckusick ip->i_flag |= ICHG; 70637737Smckusick error = iupdat(ip, &time, &time, 1); 70737737Smckusick if (!error) 70837737Smckusick error = direnter(ip, ndp); 70937737Smckusick if (ndp->ni_dvp != vp) 71037737Smckusick IUNLOCK(ip); 71149737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 71247219Smckusick vput(ndp->ni_dvp); 71337737Smckusick if (error) { 71437737Smckusick ip->i_nlink--; 71530598Smckusick ip->i_flag |= ICHG; 71637737Smckusick } 71737737Smckusick return (error); 7189167Ssam } 7199167Ssam 7209167Ssam /* 7219167Ssam * Rename system call. 7229167Ssam * rename("foo", "bar"); 7239167Ssam * is essentially 7249167Ssam * unlink("bar"); 7259167Ssam * link("foo", "bar"); 7269167Ssam * unlink("foo"); 7279167Ssam * but ``atomically''. Can't do full commit without saving state in the 7289167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7299167Ssam * always guarantee the target exists. 7309167Ssam * 7319167Ssam * Basic algorithm is: 7329167Ssam * 7339167Ssam * 1) Bump link count on source while we're linking it to the 73437737Smckusick * target. This also ensure the inode won't be deleted out 73516776Smckusick * from underneath us while we work (it may be truncated by 73616776Smckusick * a concurrent `trunc' or `open' for creation). 7379167Ssam * 2) Link source to destination. If destination already exists, 7389167Ssam * delete it first. 73916776Smckusick * 3) Unlink source reference to inode if still around. If a 74016776Smckusick * directory was moved and the parent of the destination 7419167Ssam * is different from the source, patch the ".." entry in the 7429167Ssam * directory. 7439167Ssam */ 74448039Smckusick ufs_rename(fndp, tndp, p) 74537737Smckusick register struct nameidata *fndp, *tndp; 74648039Smckusick struct proc *p; 7477701Ssam { 7489167Ssam register struct inode *ip, *xp, *dp; 74916776Smckusick struct dirtemplate dirbuf; 75016776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 75110051Ssam int error = 0; 7527701Ssam 75349737Smckusick #ifdef DIANOSTIC 75449737Smckusick if ((tndp->ni_nameiop & HASBUF) == 0 || 75549737Smckusick (fndp->ni_nameiop & HASBUF) == 0) 75649737Smckusick panic("ufs_rename: no name"); 75749737Smckusick #endif 75837737Smckusick dp = VTOI(fndp->ni_dvp); 75937737Smckusick ip = VTOI(fndp->ni_vp); 76049737Smckusick /* 76149737Smckusick * Check if just deleting a link name. 76249737Smckusick */ 76349737Smckusick if (fndp->ni_vp == tndp->ni_vp) { 76449737Smckusick VOP_ABORTOP(tndp); 76549737Smckusick vput(tndp->ni_dvp); 76649737Smckusick vput(tndp->ni_vp); 76749737Smckusick vrele(fndp->ni_dvp); 76849737Smckusick if ((ip->i_mode&IFMT) == IFDIR) { 76949737Smckusick VOP_ABORTOP(fndp); 77049737Smckusick vrele(fndp->ni_vp); 77149737Smckusick return (EINVAL); 77249737Smckusick } 77349737Smckusick doingdirectory = 0; 77449737Smckusick goto unlinkit; 77549737Smckusick } 77637737Smckusick ILOCK(ip); 7779167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 7789167Ssam /* 77911641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 7809167Ssam */ 78149737Smckusick if ((fndp->ni_namelen == 1 && fndp->ni_ptr[0] == '.') || 78249737Smckusick dp == ip || fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { 78342466Smckusick VOP_ABORTOP(tndp); 78442466Smckusick vput(tndp->ni_dvp); 78542466Smckusick if (tndp->ni_vp) 78642466Smckusick vput(tndp->ni_vp); 78742466Smckusick VOP_ABORTOP(fndp); 78842466Smckusick vrele(fndp->ni_dvp); 78942466Smckusick vput(fndp->ni_vp); 79037737Smckusick return (EINVAL); 7919167Ssam } 79216776Smckusick ip->i_flag |= IRENAME; 7939167Ssam oldparent = dp->i_number; 7949167Ssam doingdirectory++; 7959167Ssam } 79637737Smckusick vrele(fndp->ni_dvp); 7979167Ssam 7989167Ssam /* 7999167Ssam * 1) Bump link count while we're moving stuff 8009167Ssam * around. If we crash somewhere before 8019167Ssam * completing our work, the link count 8029167Ssam * may be wrong, but correctable. 8039167Ssam */ 8049167Ssam ip->i_nlink++; 8059167Ssam ip->i_flag |= ICHG; 80637737Smckusick error = iupdat(ip, &time, &time, 1); 80716664Smckusick IUNLOCK(ip); 8089167Ssam 8099167Ssam /* 8109167Ssam * When the target exists, both the directory 81137737Smckusick * and target vnodes are returned locked. 8129167Ssam */ 81337737Smckusick dp = VTOI(tndp->ni_dvp); 81437737Smckusick xp = NULL; 81537737Smckusick if (tndp->ni_vp) 81637737Smckusick xp = VTOI(tndp->ni_vp); 8179167Ssam /* 81811641Ssam * If ".." must be changed (ie the directory gets a new 81912816Smckusick * parent) then the source directory must not be in the 82012816Smckusick * directory heirarchy above the target, as this would 82112816Smckusick * orphan everything below the source directory. Also 82212816Smckusick * the user must have write permission in the source so 82312816Smckusick * as to be able to change "..". We must repeat the call 82412816Smckusick * to namei, as the parent directory is unlocked by the 82512816Smckusick * call to checkpath(). 82611641Ssam */ 82716776Smckusick if (oldparent != dp->i_number) 82816776Smckusick newparent = dp->i_number; 82916776Smckusick if (doingdirectory && newparent) { 83041466Smckusick VOP_LOCK(fndp->ni_vp); 83148039Smckusick error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred, p); 83241466Smckusick VOP_UNLOCK(fndp->ni_vp); 83341466Smckusick if (error) 83412816Smckusick goto bad; 83549737Smckusick if (xp != NULL) 83649737Smckusick iput(xp); 83749737Smckusick if (error = checkpath(ip, dp, tndp->ni_cred)) 83849737Smckusick goto out; 83949737Smckusick if ((tndp->ni_nameiop & SAVESTART) == 0) 84049737Smckusick panic("ufs_rename: lost to startdir"); 84149737Smckusick if (error = lookup(tndp, p)) 84249737Smckusick goto out; 84349737Smckusick dp = VTOI(tndp->ni_dvp); 84449737Smckusick xp = NULL; 84549737Smckusick if (tndp->ni_vp) 84649737Smckusick xp = VTOI(tndp->ni_vp); 84712816Smckusick } 84811641Ssam /* 8499167Ssam * 2) If target doesn't exist, link the target 8509167Ssam * to the source and unlink the source. 8519167Ssam * Otherwise, rewrite the target directory 8529167Ssam * entry to reference the source inode and 8539167Ssam * expunge the original entry's existence. 8549167Ssam */ 8559167Ssam if (xp == NULL) { 85637737Smckusick if (dp->i_dev != ip->i_dev) 85737737Smckusick panic("rename: EXDEV"); 8589167Ssam /* 85916776Smckusick * Account for ".." in new directory. 86016776Smckusick * When source and destination have the same 86116776Smckusick * parent we don't fool with the link count. 8629167Ssam */ 86316776Smckusick if (doingdirectory && newparent) { 86446251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 86546251Smckusick error = EMLINK; 86646251Smckusick goto bad; 86746251Smckusick } 8689167Ssam dp->i_nlink++; 8699167Ssam dp->i_flag |= ICHG; 87046251Smckusick if (error = iupdat(dp, &time, &time, 1)) 87146251Smckusick goto bad; 8729167Ssam } 87347219Smckusick if (error = direnter(ip, tndp)) { 87447219Smckusick if (doingdirectory && newparent) { 87547219Smckusick dp->i_nlink--; 87647219Smckusick dp->i_flag |= ICHG; 87747219Smckusick (void) iupdat(dp, &time, &time, 1); 87847219Smckusick } 87947219Smckusick goto bad; 88047219Smckusick } 88147234Smckusick iput(dp); 8829167Ssam } else { 88337737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 88437737Smckusick panic("rename: EXDEV"); 8859167Ssam /* 88610590Ssam * Short circuit rename(foo, foo). 88710590Ssam */ 88810590Ssam if (xp->i_number == ip->i_number) 88937737Smckusick panic("rename: same file"); 89010590Ssam /* 89124433Sbloom * If the parent directory is "sticky", then the user must 89224433Sbloom * own the parent directory, or the destination of the rename, 89324433Sbloom * otherwise the destination may not be changed (except by 89424433Sbloom * root). This implements append-only directories. 89524433Sbloom */ 89637737Smckusick if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && 89737737Smckusick tndp->ni_cred->cr_uid != dp->i_uid && 89837737Smckusick xp->i_uid != tndp->ni_cred->cr_uid) { 89924433Sbloom error = EPERM; 90024433Sbloom goto bad; 90124433Sbloom } 90224433Sbloom /* 90349737Smckusick * Target must be empty if a directory and have no links 90449737Smckusick * to it. Also, ensure source and target are compatible 90549737Smckusick * (both directories, or both not directories). 9069167Ssam */ 9079167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 90837737Smckusick if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 90937737Smckusick xp->i_nlink > 2) { 91010051Ssam error = ENOTEMPTY; 9119167Ssam goto bad; 9129167Ssam } 9139167Ssam if (!doingdirectory) { 91410051Ssam error = ENOTDIR; 9159167Ssam goto bad; 9169167Ssam } 91737737Smckusick cache_purge(ITOV(dp)); 9189167Ssam } else if (doingdirectory) { 91910051Ssam error = EISDIR; 9209167Ssam goto bad; 9219167Ssam } 92237737Smckusick if (error = dirrewrite(dp, ip, tndp)) 92337737Smckusick goto bad; 92445354Smckusick /* 92545354Smckusick * If the target directory is in the same 92645354Smckusick * directory as the source directory, 92745354Smckusick * decrement the link count on the parent 92845354Smckusick * of the target directory. 92945354Smckusick */ 93045354Smckusick if (doingdirectory && !newparent) { 93145354Smckusick dp->i_nlink--; 93245354Smckusick dp->i_flag |= ICHG; 93345354Smckusick } 93437737Smckusick vput(ITOV(dp)); 9359167Ssam /* 93610051Ssam * Adjust the link count of the target to 93710051Ssam * reflect the dirrewrite above. If this is 93810051Ssam * a directory it is empty and there are 93910051Ssam * no links to it, so we can squash the inode and 94010051Ssam * any space associated with it. We disallowed 94110051Ssam * renaming over top of a directory with links to 94216776Smckusick * it above, as the remaining link would point to 94316776Smckusick * a directory without "." or ".." entries. 9449167Ssam */ 94510051Ssam xp->i_nlink--; 9469167Ssam if (doingdirectory) { 94710051Ssam if (--xp->i_nlink != 0) 94810051Ssam panic("rename: linked directory"); 94939674Smckusick error = itrunc(xp, (u_long)0, IO_SYNC); 95010051Ssam } 9519167Ssam xp->i_flag |= ICHG; 95238398Smckusick iput(xp); 95310246Ssam xp = NULL; 9549167Ssam } 9559167Ssam 9569167Ssam /* 9579167Ssam * 3) Unlink the source. 9589167Ssam */ 95949737Smckusick unlinkit: 96049737Smckusick fndp->ni_nameiop &= ~MODMASK; 96149737Smckusick fndp->ni_nameiop |= LOCKPARENT | LOCKLEAF; 96249737Smckusick if ((fndp->ni_nameiop & SAVESTART) == 0) 96349737Smckusick panic("ufs_rename: lost from startdir"); 96449737Smckusick (void) lookup(fndp, p); 96537737Smckusick if (fndp->ni_vp != NULL) { 96637737Smckusick xp = VTOI(fndp->ni_vp); 96737737Smckusick dp = VTOI(fndp->ni_dvp); 96837737Smckusick } else { 96946250Smckusick /* 97046250Smckusick * From name has disappeared. 97146250Smckusick */ 97246250Smckusick if (doingdirectory) 97346250Smckusick panic("rename: lost dir entry"); 97446250Smckusick vrele(ITOV(ip)); 97546250Smckusick return (0); 97637737Smckusick } 9779167Ssam /* 97837737Smckusick * Ensure that the directory entry still exists and has not 97916776Smckusick * changed while the new name has been entered. If the source is 98016776Smckusick * a file then the entry may have been unlinked or renamed. In 98116776Smckusick * either case there is no further work to be done. If the source 98216776Smckusick * is a directory then it cannot have been rmdir'ed; its link 98316776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 98437737Smckusick * The IRENAME flag ensures that it cannot be moved by another 98516776Smckusick * rename. 9869167Ssam */ 98717758Smckusick if (xp != ip) { 98816776Smckusick if (doingdirectory) 98917758Smckusick panic("rename: lost dir entry"); 99016776Smckusick } else { 9919167Ssam /* 99216776Smckusick * If the source is a directory with a 99316776Smckusick * new parent, the link count of the old 99416776Smckusick * parent directory must be decremented 99516776Smckusick * and ".." set to point to the new parent. 9969167Ssam */ 99716776Smckusick if (doingdirectory && newparent) { 9989167Ssam dp->i_nlink--; 9999167Ssam dp->i_flag |= ICHG; 100039597Smckusick error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, 100137737Smckusick sizeof (struct dirtemplate), (off_t)0, 100239597Smckusick UIO_SYSSPACE, IO_NODELOCKED, 100348039Smckusick tndp->ni_cred, (int *)0, (struct proc *)0); 100416776Smckusick if (error == 0) { 100516776Smckusick if (dirbuf.dotdot_namlen != 2 || 100616776Smckusick dirbuf.dotdot_name[0] != '.' || 100716776Smckusick dirbuf.dotdot_name[1] != '.') { 100839610Smckusick dirbad(xp, 12, "rename: mangled dir"); 100916776Smckusick } else { 101016776Smckusick dirbuf.dotdot_ino = newparent; 101139597Smckusick (void) vn_rdwr(UIO_WRITE, ITOV(xp), 101216776Smckusick (caddr_t)&dirbuf, 101316776Smckusick sizeof (struct dirtemplate), 101437740Smckusick (off_t)0, UIO_SYSSPACE, 101539597Smckusick IO_NODELOCKED|IO_SYNC, 101648039Smckusick tndp->ni_cred, (int *)0, 101748039Smckusick (struct proc *)0); 101837737Smckusick cache_purge(ITOV(dp)); 101916776Smckusick } 102016776Smckusick } 10219167Ssam } 102237737Smckusick error = dirremove(fndp); 102337737Smckusick if (!error) { 102416776Smckusick xp->i_nlink--; 102516776Smckusick xp->i_flag |= ICHG; 10269167Ssam } 102716776Smckusick xp->i_flag &= ~IRENAME; 10289167Ssam } 10299167Ssam if (dp) 103037737Smckusick vput(ITOV(dp)); 103116776Smckusick if (xp) 103237737Smckusick vput(ITOV(xp)); 103337737Smckusick vrele(ITOV(ip)); 103437737Smckusick return (error); 10359167Ssam 10369167Ssam bad: 10379167Ssam if (xp) 103837737Smckusick vput(ITOV(xp)); 103937737Smckusick vput(ITOV(dp)); 10409167Ssam out: 10419167Ssam ip->i_nlink--; 10429167Ssam ip->i_flag |= ICHG; 104337737Smckusick vrele(ITOV(ip)); 104437737Smckusick return (error); 10457701Ssam } 10467701Ssam 10477535Sroot /* 104812756Ssam * A virgin directory (no blushing please). 104912756Ssam */ 105012756Ssam struct dirtemplate mastertemplate = { 105112756Ssam 0, 12, 1, ".", 105212756Ssam 0, DIRBLKSIZ - 12, 2, ".." 105312756Ssam }; 105412756Ssam 105512756Ssam /* 105612756Ssam * Mkdir system call 105712756Ssam */ 105848039Smckusick ufs_mkdir(ndp, vap, p) 105937737Smckusick struct nameidata *ndp; 106037737Smckusick struct vattr *vap; 106148039Smckusick struct proc *p; 106212756Ssam { 106312756Ssam register struct inode *ip, *dp; 106437737Smckusick struct inode *tip; 106537737Smckusick struct vnode *dvp; 106612756Ssam struct dirtemplate dirtemplate; 106737737Smckusick int error; 106837737Smckusick int dmode; 106912756Ssam 107049737Smckusick #ifdef DIANOSTIC 107149737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 107249737Smckusick panic("ufs_mkdir: no name"); 107349737Smckusick #endif 107437737Smckusick dvp = ndp->ni_dvp; 107537737Smckusick dp = VTOI(dvp); 107646251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 107749737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 107846251Smckusick iput(dp); 107946251Smckusick return (EMLINK); 108046251Smckusick } 108137737Smckusick dmode = vap->va_mode&0777; 108237737Smckusick dmode |= IFDIR; 108312756Ssam /* 108449737Smckusick * Must simulate part of maknode here to acquire the inode, but 108549737Smckusick * not have it entered in the parent directory. The entry is made 108649737Smckusick * later after writing "." and ".." entries. 108712756Ssam */ 108841312Smckusick if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { 108949737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 109012756Ssam iput(dp); 109137737Smckusick return (error); 109212756Ssam } 109337737Smckusick ip = tip; 109441312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 109541312Smckusick ip->i_gid = dp->i_gid; 109612756Ssam #ifdef QUOTA 109741312Smckusick if ((error = getinoquota(ip)) || 109841312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 109949737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 110041312Smckusick ifree(ip, ip->i_number, dmode); 110141312Smckusick iput(ip); 110241312Smckusick iput(dp); 110341312Smckusick return (error); 110441312Smckusick } 110512756Ssam #endif 110612756Ssam ip->i_flag |= IACC|IUPD|ICHG; 110737737Smckusick ip->i_mode = dmode; 110837737Smckusick ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ 110912756Ssam ip->i_nlink = 2; 111037737Smckusick error = iupdat(ip, &time, &time, 1); 111112756Ssam 111212756Ssam /* 111312756Ssam * Bump link count in parent directory 111412756Ssam * to reflect work done below. Should 111512756Ssam * be done before reference is created 111612756Ssam * so reparation is possible if we crash. 111712756Ssam */ 111812756Ssam dp->i_nlink++; 111912756Ssam dp->i_flag |= ICHG; 112047219Smckusick if (error = iupdat(dp, &time, &time, 1)) 112147219Smckusick goto bad; 112212756Ssam 112312756Ssam /* 112412756Ssam * Initialize directory with "." 112512756Ssam * and ".." from static template. 112612756Ssam */ 112712756Ssam dirtemplate = mastertemplate; 112812756Ssam dirtemplate.dot_ino = ip->i_number; 112912756Ssam dirtemplate.dotdot_ino = dp->i_number; 113039597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, 113148039Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 113248039Smckusick IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0, (struct proc *)0); 113337737Smckusick if (error) { 113412756Ssam dp->i_nlink--; 113512756Ssam dp->i_flag |= ICHG; 113612756Ssam goto bad; 113712756Ssam } 113843288Smckusick if (DIRBLKSIZ > dp->i_fs->fs_fsize) { 113937737Smckusick panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ 114043288Smckusick } else { 114118103Smckusick ip->i_size = DIRBLKSIZ; 114243288Smckusick ip->i_flag |= ICHG; 114343288Smckusick } 114412756Ssam /* 114512756Ssam * Directory all set up, now 114612756Ssam * install the entry for it in 114712756Ssam * the parent directory. 114812756Ssam */ 114947219Smckusick if (error = direnter(ip, ndp)) { 115047657Smckusick dp->i_nlink--; 115147657Smckusick dp->i_flag |= ICHG; 115212756Ssam } 115312756Ssam bad: 115412756Ssam /* 115512756Ssam * No need to do an explicit itrunc here, 115637737Smckusick * vrele will do this for us because we set 115712756Ssam * the link count to 0. 115812756Ssam */ 115937737Smckusick if (error) { 116012756Ssam ip->i_nlink = 0; 116112756Ssam ip->i_flag |= ICHG; 116238144Smckusick iput(ip); 116338144Smckusick } else 116438144Smckusick ndp->ni_vp = ITOV(ip); 116549737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 116647219Smckusick iput(dp); 116737737Smckusick return (error); 116812756Ssam } 116912756Ssam 117012756Ssam /* 117112756Ssam * Rmdir system call. 117212756Ssam */ 117348039Smckusick ufs_rmdir(ndp, p) 117437737Smckusick register struct nameidata *ndp; 117548039Smckusick struct proc *p; 117612756Ssam { 117712756Ssam register struct inode *ip, *dp; 117837737Smckusick int error = 0; 117912756Ssam 118037737Smckusick ip = VTOI(ndp->ni_vp); 118137737Smckusick dp = VTOI(ndp->ni_dvp); 118212756Ssam /* 118312756Ssam * No rmdir "." please. 118412756Ssam */ 118512756Ssam if (dp == ip) { 118637737Smckusick vrele(ITOV(dp)); 118712756Ssam iput(ip); 118837737Smckusick return (EINVAL); 118912756Ssam } 119012756Ssam /* 119112756Ssam * Verify the directory is empty (and valid). 119212756Ssam * (Rmdir ".." won't be valid since 119312756Ssam * ".." will contain a reference to 119412756Ssam * the current directory and thus be 119512756Ssam * non-empty.) 119612756Ssam */ 119737737Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { 119837737Smckusick error = ENOTEMPTY; 119912756Ssam goto out; 120012756Ssam } 120112756Ssam /* 120212756Ssam * Delete reference to directory before purging 120312756Ssam * inode. If we crash in between, the directory 120412756Ssam * will be reattached to lost+found, 120512756Ssam */ 120637737Smckusick if (error = dirremove(ndp)) 120712756Ssam goto out; 120812756Ssam dp->i_nlink--; 120912756Ssam dp->i_flag |= ICHG; 121037737Smckusick cache_purge(ITOV(dp)); 121112756Ssam iput(dp); 121237737Smckusick ndp->ni_dvp = NULL; 121312756Ssam /* 121412756Ssam * Truncate inode. The only stuff left 121512756Ssam * in the directory is "." and "..". The 121612756Ssam * "." reference is inconsequential since 121712756Ssam * we're quashing it. The ".." reference 121812756Ssam * has already been adjusted above. We've 121912756Ssam * removed the "." reference and the reference 122012756Ssam * in the parent directory, but there may be 122112756Ssam * other hard links so decrement by 2 and 122212756Ssam * worry about them later. 122312756Ssam */ 122412756Ssam ip->i_nlink -= 2; 122539674Smckusick error = itrunc(ip, (u_long)0, IO_SYNC); 122637737Smckusick cache_purge(ITOV(ip)); 122712756Ssam out: 122837737Smckusick if (ndp->ni_dvp) 122912756Ssam iput(dp); 123012756Ssam iput(ip); 123137737Smckusick return (error); 123212756Ssam } 123312756Ssam 123437737Smckusick /* 123537737Smckusick * symlink -- make a symbolic link 123637737Smckusick */ 123748039Smckusick ufs_symlink(ndp, vap, target, p) 123837737Smckusick struct nameidata *ndp; 123937737Smckusick struct vattr *vap; 124037737Smckusick char *target; 124148039Smckusick struct proc *p; 124212756Ssam { 124337737Smckusick struct inode *ip; 124437737Smckusick int error; 124512756Ssam 124637737Smckusick error = maknode(IFLNK | vap->va_mode, ndp, &ip); 124737737Smckusick if (error) 124837737Smckusick return (error); 124939597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, 125048039Smckusick UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0, 125148039Smckusick (struct proc *)0); 125237737Smckusick iput(ip); 125337737Smckusick return (error); 125437737Smckusick } 125537737Smckusick 125637737Smckusick /* 125737737Smckusick * Vnode op for read and write 125837737Smckusick */ 125940345Smckusick ufs_readdir(vp, uio, cred, eofflagp) 126037737Smckusick struct vnode *vp; 126137737Smckusick register struct uio *uio; 126237737Smckusick struct ucred *cred; 126340345Smckusick int *eofflagp; 126437737Smckusick { 126539597Smckusick int count, lost, error; 126637737Smckusick 126737737Smckusick count = uio->uio_resid; 126837737Smckusick count &= ~(DIRBLKSIZ - 1); 126939597Smckusick lost = uio->uio_resid - count; 127039597Smckusick if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) 127137737Smckusick return (EINVAL); 127237737Smckusick uio->uio_resid = count; 127337737Smckusick uio->uio_iov->iov_len = count; 127439597Smckusick error = ufs_read(vp, uio, 0, cred); 127539597Smckusick uio->uio_resid += lost; 127640345Smckusick if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) 127740345Smckusick *eofflagp = 1; 127840345Smckusick else 127940345Smckusick *eofflagp = 0; 128037737Smckusick return (error); 128137737Smckusick } 128237737Smckusick 128337737Smckusick /* 128437737Smckusick * Return target name of a symbolic link 128537737Smckusick */ 128637737Smckusick ufs_readlink(vp, uiop, cred) 128737737Smckusick struct vnode *vp; 128837737Smckusick struct uio *uiop; 128937737Smckusick struct ucred *cred; 129037737Smckusick { 129137737Smckusick 129239597Smckusick return (ufs_read(vp, uiop, 0, cred)); 129337737Smckusick } 129437737Smckusick 129537737Smckusick /* 129637737Smckusick * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 129749737Smckusick * done. If a buffer has been saved in anticipation of a CREATE, delete it. 129837737Smckusick */ 129942466Smckusick /* ARGSUSED */ 130037737Smckusick ufs_abortop(ndp) 130142466Smckusick struct nameidata *ndp; 130237737Smckusick { 130337737Smckusick 130449737Smckusick if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF) 130549737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 130642466Smckusick return (0); 130712756Ssam } 130812756Ssam 130939909Smckusick /* 131039909Smckusick * Lock an inode. 131139909Smckusick */ 131237737Smckusick ufs_lock(vp) 131337737Smckusick struct vnode *vp; 131437737Smckusick { 131537737Smckusick register struct inode *ip = VTOI(vp); 131637737Smckusick 131737737Smckusick ILOCK(ip); 131837737Smckusick return (0); 131937737Smckusick } 132037737Smckusick 132139909Smckusick /* 132239909Smckusick * Unlock an inode. 132339909Smckusick */ 132437737Smckusick ufs_unlock(vp) 132537737Smckusick struct vnode *vp; 132637737Smckusick { 132737737Smckusick register struct inode *ip = VTOI(vp); 132837737Smckusick 132937737Smckusick if (!(ip->i_flag & ILOCKED)) 133037737Smckusick panic("ufs_unlock NOT LOCKED"); 133137737Smckusick IUNLOCK(ip); 133237737Smckusick return (0); 133337737Smckusick } 133437737Smckusick 133512756Ssam /* 133639909Smckusick * Check for a locked inode. 133739909Smckusick */ 133839909Smckusick ufs_islocked(vp) 133939909Smckusick struct vnode *vp; 134039909Smckusick { 134139909Smckusick 134239909Smckusick if (VTOI(vp)->i_flag & ILOCKED) 134339909Smckusick return (1); 134439909Smckusick return (0); 134539909Smckusick } 134639909Smckusick 134739909Smckusick /* 134837737Smckusick * Get access to bmap 134912756Ssam */ 135037737Smckusick ufs_bmap(vp, bn, vpp, bnp) 135137737Smckusick struct vnode *vp; 135237737Smckusick daddr_t bn; 135337737Smckusick struct vnode **vpp; 135437737Smckusick daddr_t *bnp; 135512756Ssam { 135637737Smckusick struct inode *ip = VTOI(vp); 135712756Ssam 135837737Smckusick if (vpp != NULL) 135937737Smckusick *vpp = ip->i_devvp; 136037737Smckusick if (bnp == NULL) 136137737Smckusick return (0); 136241538Smckusick return (bmap(ip, bn, bnp)); 136312756Ssam } 136437737Smckusick 136537737Smckusick /* 136641538Smckusick * Calculate the logical to physical mapping if not done already, 136741538Smckusick * then call the device strategy routine. 136837737Smckusick */ 136941538Smckusick int checkoverlap = 0; 137039674Smckusick 137137737Smckusick ufs_strategy(bp) 137237737Smckusick register struct buf *bp; 137337737Smckusick { 137439674Smckusick register struct inode *ip = VTOI(bp->b_vp); 137539674Smckusick struct vnode *vp; 137639674Smckusick int error; 137739674Smckusick 137839674Smckusick if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 137939674Smckusick panic("ufs_strategy: spec"); 138039674Smckusick if (bp->b_blkno == bp->b_lblkno) { 138139674Smckusick if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno)) 138239674Smckusick return (error); 138339896Smckusick if ((long)bp->b_blkno == -1) 138439674Smckusick clrbuf(bp); 138539674Smckusick } 138639896Smckusick if ((long)bp->b_blkno == -1) { 138739896Smckusick biodone(bp); 138839674Smckusick return (0); 138939896Smckusick } 139041538Smckusick #ifdef DIAGNOSTIC 139139674Smckusick if (checkoverlap) { 139241538Smckusick register struct buf *ep; 139341538Smckusick struct buf *ebp; 139441538Smckusick daddr_t start, last; 139541538Smckusick 139639674Smckusick ebp = &buf[nbuf]; 139739674Smckusick start = bp->b_blkno; 139839674Smckusick last = start + btodb(bp->b_bcount) - 1; 139939674Smckusick for (ep = buf; ep < ebp; ep++) { 140039674Smckusick if (ep == bp || (ep->b_flags & B_INVAL) || 140141396Smckusick ep->b_vp == NULLVP) 140239674Smckusick continue; 140339674Smckusick if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0)) 140439674Smckusick continue; 140539674Smckusick if (vp != ip->i_devvp) 140639674Smckusick continue; 140739674Smckusick /* look for overlap */ 140839674Smckusick if (ep->b_bcount == 0 || ep->b_blkno > last || 140939674Smckusick ep->b_blkno + btodb(ep->b_bcount) <= start) 141039674Smckusick continue; 141139896Smckusick vprint("Disk overlap", vp); 141239896Smckusick printf("\tstart %d, end %d overlap start %d, end %d\n", 141339896Smckusick start, last, ep->b_blkno, 141439896Smckusick ep->b_blkno + btodb(ep->b_bcount) - 1); 141541538Smckusick panic("Disk buffer overlap"); 141639674Smckusick } 141739674Smckusick } 141841538Smckusick #endif /* DIAGNOSTIC */ 141939674Smckusick vp = ip->i_devvp; 142039674Smckusick bp->b_dev = vp->v_rdev; 1421*49762Smckusick (*(vp->v_op->vop_strategy))(bp); 142237737Smckusick return (0); 142337737Smckusick } 142437737Smckusick 142537737Smckusick /* 142639674Smckusick * Print out the contents of an inode. 142739674Smckusick */ 142839674Smckusick ufs_print(vp) 142939674Smckusick struct vnode *vp; 143039674Smckusick { 143139674Smckusick register struct inode *ip = VTOI(vp); 143239674Smckusick 143340293Smckusick printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number, 143440293Smckusick major(ip->i_dev), minor(ip->i_dev)); 143540293Smckusick #ifdef FIFO 143640293Smckusick if (vp->v_type == VFIFO) 143740293Smckusick fifo_printinfo(vp); 143840293Smckusick #endif /* FIFO */ 143940293Smckusick printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : ""); 144039900Smckusick if (ip->i_spare0 == 0) 144139900Smckusick return; 144239900Smckusick printf("\towner pid %d", ip->i_spare0); 144339900Smckusick if (ip->i_spare1) 144439900Smckusick printf(" waiting pid %d", ip->i_spare1); 144539900Smckusick printf("\n"); 144639674Smckusick } 144739674Smckusick 144839674Smckusick /* 144939628Smckusick * Read wrapper for special devices. 145039628Smckusick */ 145139628Smckusick ufsspec_read(vp, uio, ioflag, cred) 145239628Smckusick struct vnode *vp; 145339628Smckusick struct uio *uio; 145439628Smckusick int ioflag; 145539628Smckusick struct ucred *cred; 145639628Smckusick { 145739628Smckusick 145839628Smckusick /* 145939628Smckusick * Set access flag. 146039628Smckusick */ 146139628Smckusick VTOI(vp)->i_flag |= IACC; 146239628Smckusick return (spec_read(vp, uio, ioflag, cred)); 146339628Smckusick } 146439628Smckusick 146539628Smckusick /* 146639628Smckusick * Write wrapper for special devices. 146739628Smckusick */ 146839628Smckusick ufsspec_write(vp, uio, ioflag, cred) 146939628Smckusick struct vnode *vp; 147039628Smckusick struct uio *uio; 147139628Smckusick int ioflag; 147239628Smckusick struct ucred *cred; 147339628Smckusick { 147439628Smckusick 147539628Smckusick /* 147639628Smckusick * Set update and change flags. 147739628Smckusick */ 147839628Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 147939628Smckusick return (spec_write(vp, uio, ioflag, cred)); 148039628Smckusick } 148139628Smckusick 148239628Smckusick /* 148339628Smckusick * Close wrapper for special devices. 148439628Smckusick * 148539628Smckusick * Update the times on the inode then do device close. 148639628Smckusick */ 148748039Smckusick ufsspec_close(vp, fflag, cred, p) 148839628Smckusick struct vnode *vp; 148939628Smckusick int fflag; 149039628Smckusick struct ucred *cred; 149148039Smckusick struct proc *p; 149239628Smckusick { 149339628Smckusick register struct inode *ip = VTOI(vp); 149439628Smckusick 149539815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 149639628Smckusick ITIMES(ip, &time, &time); 149748039Smckusick return (spec_close(vp, fflag, cred, p)); 149839628Smckusick } 149939628Smckusick 150040290Smckusick #ifdef FIFO 150139628Smckusick /* 150240290Smckusick * Read wrapper for fifo's 150340290Smckusick */ 150440290Smckusick ufsfifo_read(vp, uio, ioflag, cred) 150540290Smckusick struct vnode *vp; 150640290Smckusick struct uio *uio; 150740290Smckusick int ioflag; 150840290Smckusick struct ucred *cred; 150940290Smckusick { 151040290Smckusick 151140290Smckusick /* 151240290Smckusick * Set access flag. 151340290Smckusick */ 151440290Smckusick VTOI(vp)->i_flag |= IACC; 151540290Smckusick return (fifo_read(vp, uio, ioflag, cred)); 151640290Smckusick } 151740290Smckusick 151840290Smckusick /* 151940290Smckusick * Write wrapper for fifo's. 152040290Smckusick */ 152140290Smckusick ufsfifo_write(vp, uio, ioflag, cred) 152240290Smckusick struct vnode *vp; 152340290Smckusick struct uio *uio; 152440290Smckusick int ioflag; 152540290Smckusick struct ucred *cred; 152640290Smckusick { 152740290Smckusick 152840290Smckusick /* 152940290Smckusick * Set update and change flags. 153040290Smckusick */ 153140290Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 153240290Smckusick return (fifo_write(vp, uio, ioflag, cred)); 153340290Smckusick } 153440290Smckusick 153540290Smckusick /* 153640290Smckusick * Close wrapper for fifo's. 153740290Smckusick * 153840290Smckusick * Update the times on the inode then do device close. 153940290Smckusick */ 154048039Smckusick ufsfifo_close(vp, fflag, cred, p) 154140290Smckusick struct vnode *vp; 154240290Smckusick int fflag; 154340290Smckusick struct ucred *cred; 154448039Smckusick struct proc *p; 154540290Smckusick { 154640290Smckusick register struct inode *ip = VTOI(vp); 154740290Smckusick 154840290Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 154940290Smckusick ITIMES(ip, &time, &time); 155048039Smckusick return (fifo_close(vp, fflag, cred, p)); 155140290Smckusick } 155240290Smckusick #endif /* FIFO */ 155340290Smckusick 155440290Smckusick /* 155549452Smckusick * Allocate a new inode. 155637737Smckusick */ 155737737Smckusick maknode(mode, ndp, ipp) 155837737Smckusick int mode; 155937737Smckusick register struct nameidata *ndp; 156037737Smckusick struct inode **ipp; 156137737Smckusick { 156237737Smckusick register struct inode *ip; 156337737Smckusick struct inode *tip; 156437737Smckusick register struct inode *pdir = VTOI(ndp->ni_dvp); 156537737Smckusick ino_t ipref; 156637737Smckusick int error; 156737737Smckusick 156849737Smckusick #ifdef DIANOSTIC 156949737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 157049737Smckusick panic("maknode: no name"); 157149737Smckusick #endif 157237737Smckusick *ipp = 0; 157341312Smckusick if ((mode & IFMT) == 0) 157441312Smckusick mode |= IFREG; 157537737Smckusick if ((mode & IFMT) == IFDIR) 157637737Smckusick ipref = dirpref(pdir->i_fs); 157737737Smckusick else 157837737Smckusick ipref = pdir->i_number; 157941312Smckusick if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { 158049737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 158137737Smckusick iput(pdir); 158237737Smckusick return (error); 158337737Smckusick } 158437737Smckusick ip = tip; 158541312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 158641312Smckusick ip->i_gid = pdir->i_gid; 158737737Smckusick #ifdef QUOTA 158841312Smckusick if ((error = getinoquota(ip)) || 158941312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 159049737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 159141312Smckusick ifree(ip, ip->i_number, mode); 159241312Smckusick iput(ip); 159341312Smckusick iput(pdir); 159441312Smckusick return (error); 159541312Smckusick } 159637737Smckusick #endif 159737737Smckusick ip->i_flag |= IACC|IUPD|ICHG; 159837737Smckusick ip->i_mode = mode; 159937737Smckusick ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ 160037737Smckusick ip->i_nlink = 1; 160137737Smckusick if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && 160237737Smckusick suser(ndp->ni_cred, NULL)) 160337737Smckusick ip->i_mode &= ~ISGID; 160437737Smckusick 160537737Smckusick /* 160637737Smckusick * Make sure inode goes to disk before directory entry. 160737737Smckusick */ 160841312Smckusick if (error = iupdat(ip, &time, &time, 1)) 160941312Smckusick goto bad; 161047219Smckusick if (error = direnter(ip, ndp)) 161141312Smckusick goto bad; 161249737Smckusick if ((ndp->ni_nameiop & SAVESTART) == 0) 161349737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 161447219Smckusick iput(pdir); 161537737Smckusick *ipp = ip; 161637737Smckusick return (0); 161741312Smckusick 161841312Smckusick bad: 161941312Smckusick /* 162041312Smckusick * Write error occurred trying to update the inode 162141312Smckusick * or the directory so must deallocate the inode. 162241312Smckusick */ 162349737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 162447219Smckusick iput(pdir); 162541312Smckusick ip->i_nlink = 0; 162641312Smckusick ip->i_flag |= ICHG; 162741312Smckusick iput(ip); 162841312Smckusick return (error); 162937737Smckusick } 163046207Smckusick 163146207Smckusick /* 163246207Smckusick * Advisory record locking support 163346207Smckusick */ 163446207Smckusick ufs_advlock(vp, id, op, fl, flags) 163546207Smckusick struct vnode *vp; 163646207Smckusick caddr_t id; 163746207Smckusick int op; 163846207Smckusick register struct flock *fl; 163946207Smckusick int flags; 164046207Smckusick { 164146207Smckusick register struct inode *ip = VTOI(vp); 164246207Smckusick register struct lockf *lock; 164346207Smckusick off_t start, end; 164446207Smckusick int error; 164546207Smckusick 164646207Smckusick /* 164746207Smckusick * Avoid the common case of unlocking when inode has no locks. 164846207Smckusick */ 164946207Smckusick if (ip->i_lockf == (struct lockf *)0) { 165046207Smckusick if (op != F_SETLK) { 165146207Smckusick fl->l_type = F_UNLCK; 165246207Smckusick return (0); 165346207Smckusick } 165446207Smckusick } 165546207Smckusick /* 165646207Smckusick * Convert the flock structure into a start and end. 165746207Smckusick */ 165846207Smckusick switch (fl->l_whence) { 165946207Smckusick 166046207Smckusick case SEEK_SET: 166146207Smckusick case SEEK_CUR: 166246207Smckusick /* 166346207Smckusick * Caller is responsible for adding any necessary offset 166446207Smckusick * when SEEK_CUR is used. 166546207Smckusick */ 166646207Smckusick start = fl->l_start; 166746207Smckusick break; 166846207Smckusick 166946207Smckusick case SEEK_END: 167046207Smckusick start = ip->i_size + fl->l_start; 167146207Smckusick break; 167246207Smckusick 167346207Smckusick default: 167446207Smckusick return (EINVAL); 167546207Smckusick } 167646207Smckusick if (start < 0) 167746207Smckusick return (EINVAL); 167846207Smckusick if (fl->l_len == 0) 167946207Smckusick end = -1; 168046207Smckusick else 168146507Smckusick end = start + fl->l_len - 1; 168246207Smckusick /* 168346207Smckusick * Create the lockf structure 168446207Smckusick */ 168546207Smckusick MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); 168646207Smckusick lock->lf_start = start; 168746207Smckusick lock->lf_end = end; 168846207Smckusick lock->lf_id = id; 168946207Smckusick lock->lf_inode = ip; 169046207Smckusick lock->lf_type = fl->l_type; 169146207Smckusick lock->lf_next = (struct lockf *)0; 169246207Smckusick lock->lf_block = (struct lockf *)0; 169346207Smckusick lock->lf_flags = flags; 169446207Smckusick /* 169546207Smckusick * Do the requested operation. 169646207Smckusick */ 169746207Smckusick switch(op) { 169846207Smckusick case F_SETLK: 169946679Smckusick return (lf_setlock(lock)); 170046207Smckusick 170146207Smckusick case F_UNLCK: 170246679Smckusick error = lf_clearlock(lock); 170346679Smckusick FREE(lock, M_LOCKF); 170446679Smckusick return (error); 170546207Smckusick 170646207Smckusick case F_GETLK: 170746679Smckusick error = lf_getlock(lock, fl); 170846679Smckusick FREE(lock, M_LOCKF); 170946679Smckusick return (error); 171046207Smckusick 171146207Smckusick default: 171246207Smckusick free(lock, M_LOCKF); 171346207Smckusick return (EINVAL); 171446207Smckusick } 171546207Smckusick /* NOTREACHED */ 171646207Smckusick } 171748039Smckusick 171848039Smckusick /* 171948039Smckusick * Global vfs data structures for ufs 172048039Smckusick */ 172148039Smckusick struct vnodeops ufs_vnodeops = { 172248039Smckusick ufs_lookup, /* lookup */ 172348039Smckusick ufs_create, /* create */ 172448039Smckusick ufs_mknod, /* mknod */ 172548039Smckusick ufs_open, /* open */ 172648039Smckusick ufs_close, /* close */ 172748039Smckusick ufs_access, /* access */ 172848039Smckusick ufs_getattr, /* getattr */ 172948039Smckusick ufs_setattr, /* setattr */ 173048039Smckusick ufs_read, /* read */ 173148039Smckusick ufs_write, /* write */ 173248039Smckusick ufs_ioctl, /* ioctl */ 173348039Smckusick ufs_select, /* select */ 173448039Smckusick ufs_mmap, /* mmap */ 173548039Smckusick ufs_fsync, /* fsync */ 173648039Smckusick ufs_seek, /* seek */ 173748039Smckusick ufs_remove, /* remove */ 173848039Smckusick ufs_link, /* link */ 173948039Smckusick ufs_rename, /* rename */ 174048039Smckusick ufs_mkdir, /* mkdir */ 174148039Smckusick ufs_rmdir, /* rmdir */ 174248039Smckusick ufs_symlink, /* symlink */ 174348039Smckusick ufs_readdir, /* readdir */ 174448039Smckusick ufs_readlink, /* readlink */ 174548039Smckusick ufs_abortop, /* abortop */ 174648039Smckusick ufs_inactive, /* inactive */ 174748039Smckusick ufs_reclaim, /* reclaim */ 174848039Smckusick ufs_lock, /* lock */ 174948039Smckusick ufs_unlock, /* unlock */ 175048039Smckusick ufs_bmap, /* bmap */ 175148039Smckusick ufs_strategy, /* strategy */ 175248039Smckusick ufs_print, /* print */ 175348039Smckusick ufs_islocked, /* islocked */ 175448039Smckusick ufs_advlock, /* advlock */ 175548039Smckusick }; 175648039Smckusick 175748039Smckusick struct vnodeops spec_inodeops = { 175848039Smckusick spec_lookup, /* lookup */ 175948039Smckusick spec_create, /* create */ 176048039Smckusick spec_mknod, /* mknod */ 176148039Smckusick spec_open, /* open */ 176248039Smckusick ufsspec_close, /* close */ 176348039Smckusick ufs_access, /* access */ 176448039Smckusick ufs_getattr, /* getattr */ 176548039Smckusick ufs_setattr, /* setattr */ 176648039Smckusick ufsspec_read, /* read */ 176748039Smckusick ufsspec_write, /* write */ 176848039Smckusick spec_ioctl, /* ioctl */ 176948039Smckusick spec_select, /* select */ 177048039Smckusick spec_mmap, /* mmap */ 177148039Smckusick spec_fsync, /* fsync */ 177248039Smckusick spec_seek, /* seek */ 177348039Smckusick spec_remove, /* remove */ 177448039Smckusick spec_link, /* link */ 177548039Smckusick spec_rename, /* rename */ 177648039Smckusick spec_mkdir, /* mkdir */ 177748039Smckusick spec_rmdir, /* rmdir */ 177848039Smckusick spec_symlink, /* symlink */ 177948039Smckusick spec_readdir, /* readdir */ 178048039Smckusick spec_readlink, /* readlink */ 178148039Smckusick spec_abortop, /* abortop */ 178248039Smckusick ufs_inactive, /* inactive */ 178348039Smckusick ufs_reclaim, /* reclaim */ 178448039Smckusick ufs_lock, /* lock */ 178548039Smckusick ufs_unlock, /* unlock */ 178648039Smckusick spec_bmap, /* bmap */ 178748039Smckusick spec_strategy, /* strategy */ 178848039Smckusick ufs_print, /* print */ 178948039Smckusick ufs_islocked, /* islocked */ 179048039Smckusick spec_advlock, /* advlock */ 179148039Smckusick }; 179248039Smckusick 179348039Smckusick #ifdef FIFO 179448039Smckusick struct vnodeops fifo_inodeops = { 179548039Smckusick fifo_lookup, /* lookup */ 179648039Smckusick fifo_create, /* create */ 179748039Smckusick fifo_mknod, /* mknod */ 179848039Smckusick fifo_open, /* open */ 179948039Smckusick ufsfifo_close, /* close */ 180048039Smckusick ufs_access, /* access */ 180148039Smckusick ufs_getattr, /* getattr */ 180248039Smckusick ufs_setattr, /* setattr */ 180348039Smckusick ufsfifo_read, /* read */ 180448039Smckusick ufsfifo_write, /* write */ 180548039Smckusick fifo_ioctl, /* ioctl */ 180648039Smckusick fifo_select, /* select */ 180748039Smckusick fifo_mmap, /* mmap */ 180848039Smckusick fifo_fsync, /* fsync */ 180948039Smckusick fifo_seek, /* seek */ 181048039Smckusick fifo_remove, /* remove */ 181148039Smckusick fifo_link, /* link */ 181248039Smckusick fifo_rename, /* rename */ 181348039Smckusick fifo_mkdir, /* mkdir */ 181448039Smckusick fifo_rmdir, /* rmdir */ 181548039Smckusick fifo_symlink, /* symlink */ 181648039Smckusick fifo_readdir, /* readdir */ 181748039Smckusick fifo_readlink, /* readlink */ 181848039Smckusick fifo_abortop, /* abortop */ 181948039Smckusick ufs_inactive, /* inactive */ 182048039Smckusick ufs_reclaim, /* reclaim */ 182148039Smckusick ufs_lock, /* lock */ 182248039Smckusick ufs_unlock, /* unlock */ 182348039Smckusick fifo_bmap, /* bmap */ 182448039Smckusick fifo_strategy, /* strategy */ 182548039Smckusick ufs_print, /* print */ 182648039Smckusick ufs_islocked, /* islocked */ 182748039Smckusick fifo_advlock, /* advlock */ 182848039Smckusick }; 182948039Smckusick #endif /* FIFO */ 183048039Smckusick 183148039Smckusick enum vtype iftovt_tab[16] = { 183248039Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 183348039Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 183448039Smckusick }; 183548039Smckusick int vttoif_tab[9] = { 183648039Smckusick 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT, 183748039Smckusick }; 1838