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*48039Smckusick * @(#)lfs_vnops.c 7.60 (Berkeley) 04/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" 23*48039Smckusick #include "fifo.h" 2446207Smckusick #include "malloc.h" 2537Sbill 2647571Skarels #include "lockf.h" 2747571Skarels #include "quota.h" 2847571Skarels #include "inode.h" 2947571Skarels #include "fs.h" 3047571Skarels 319167Ssam /* 3237737Smckusick * Create a regular file 339167Ssam */ 34*48039Smckusick ufs_create(ndp, vap, p) 3537737Smckusick struct nameidata *ndp; 3637737Smckusick struct vattr *vap; 37*48039Smckusick struct proc *p; 386254Sroot { 3937737Smckusick struct inode *ip; 4037737Smckusick int error; 416254Sroot 4237737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 4337737Smckusick return (error); 4437737Smckusick ndp->ni_vp = ITOV(ip); 4537737Smckusick return (0); 466254Sroot } 476254Sroot 4837Sbill /* 4937737Smckusick * Mknod vnode call 506254Sroot */ 5137737Smckusick /* ARGSUSED */ 52*48039Smckusick ufs_mknod(ndp, vap, cred, p) 5337737Smckusick struct nameidata *ndp; 5437737Smckusick struct ucred *cred; 5537737Smckusick struct vattr *vap; 56*48039Smckusick struct proc *p; 576254Sroot { 5839435Smckusick register struct vnode *vp; 5937737Smckusick struct inode *ip; 6037737Smckusick int error; 616254Sroot 6237737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 6337737Smckusick return (error); 6440290Smckusick ip->i_flag |= IACC|IUPD|ICHG; 6540290Smckusick if (vap->va_rdev != VNOVAL) { 6637737Smckusick /* 6737737Smckusick * Want to be able to use this to make badblock 6837737Smckusick * inodes, so don't truncate the dev number. 6937737Smckusick */ 7039608Smckusick ip->i_rdev = vap->va_rdev; 7112756Ssam } 7237737Smckusick /* 7337737Smckusick * Remove inode so that it will be reloaded by iget and 7437737Smckusick * checked to see if it is an alias of an existing entry 7537737Smckusick * in the inode cache. 7637737Smckusick */ 7740290Smckusick vp = ITOV(ip); 7840290Smckusick vput(vp); 7939435Smckusick vp->v_type = VNON; 8039435Smckusick vgone(vp); 8137737Smckusick return (0); 826254Sroot } 836254Sroot 846254Sroot /* 8537737Smckusick * Open called. 8637737Smckusick * 8737737Smckusick * Nothing to do. 886254Sroot */ 8937737Smckusick /* ARGSUSED */ 90*48039Smckusick ufs_open(vp, mode, cred, p) 9137737Smckusick struct vnode *vp; 9237737Smckusick int mode; 9337737Smckusick struct ucred *cred; 94*48039Smckusick struct proc *p; 956254Sroot { 966254Sroot 9737737Smckusick return (0); 986254Sroot } 996254Sroot 1006254Sroot /* 10137737Smckusick * Close called 10237737Smckusick * 10337737Smckusick * Update the times on the inode. 1046254Sroot */ 10537737Smckusick /* ARGSUSED */ 106*48039Smckusick ufs_close(vp, fflag, cred, p) 10737737Smckusick struct vnode *vp; 10837737Smckusick int fflag; 10937737Smckusick struct ucred *cred; 110*48039Smckusick struct proc *p; 1116254Sroot { 11237737Smckusick register struct inode *ip = VTOI(vp); 1136254Sroot 11439815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 11537737Smckusick ITIMES(ip, &time, &time); 11637737Smckusick return (0); 1176254Sroot } 1186254Sroot 11941312Smckusick /* 12041312Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 12141312Smckusick * The mode is shifted to select the owner/group/other fields. The 12241312Smckusick * super user is granted all permissions. 12341312Smckusick */ 124*48039Smckusick ufs_access(vp, mode, cred, p) 12537737Smckusick struct vnode *vp; 12641312Smckusick register int mode; 12737737Smckusick struct ucred *cred; 128*48039Smckusick struct proc *p; 1296254Sroot { 13041312Smckusick register struct inode *ip = VTOI(vp); 13141312Smckusick register gid_t *gp; 13241312Smckusick int i, error; 1336254Sroot 13441312Smckusick #ifdef DIAGNOSTIC 13541312Smckusick if (!VOP_ISLOCKED(vp)) { 13641312Smckusick vprint("ufs_access: not locked", vp); 13741312Smckusick panic("ufs_access: not locked"); 13841312Smckusick } 13941312Smckusick #endif 14041312Smckusick #ifdef QUOTA 14141312Smckusick if (mode & VWRITE) { 14241312Smckusick switch (vp->v_type) { 14341312Smckusick case VREG: case VDIR: case VLNK: 14441312Smckusick if (error = getinoquota(ip)) 14541312Smckusick return (error); 14641312Smckusick } 14741312Smckusick } 14841312Smckusick #endif /* QUOTA */ 14941312Smckusick /* 15041312Smckusick * If you're the super-user, you always get access. 15141312Smckusick */ 15241312Smckusick if (cred->cr_uid == 0) 15341312Smckusick return (0); 15441312Smckusick /* 15541312Smckusick * Access check is based on only one of owner, group, public. 15641312Smckusick * If not owner, then check group. If not a member of the 15741312Smckusick * group, then check public access. 15841312Smckusick */ 15941312Smckusick if (cred->cr_uid != ip->i_uid) { 16041312Smckusick mode >>= 3; 16141312Smckusick gp = cred->cr_groups; 16241312Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 16341312Smckusick if (ip->i_gid == *gp) 16441312Smckusick goto found; 16541312Smckusick mode >>= 3; 16641312Smckusick found: 16741312Smckusick ; 16841312Smckusick } 16941312Smckusick if ((ip->i_mode & mode) != 0) 17041312Smckusick return (0); 17141312Smckusick return (EACCES); 1726254Sroot } 1736254Sroot 17437737Smckusick /* ARGSUSED */ 175*48039Smckusick ufs_getattr(vp, vap, cred, p) 17637737Smckusick struct vnode *vp; 17737737Smckusick register struct vattr *vap; 17837737Smckusick struct ucred *cred; 179*48039Smckusick struct proc *p; 1806254Sroot { 18137737Smckusick register struct inode *ip = VTOI(vp); 1826254Sroot 18337737Smckusick ITIMES(ip, &time, &time); 1846254Sroot /* 18537737Smckusick * Copy from inode table 1866254Sroot */ 18737737Smckusick vap->va_fsid = ip->i_dev; 18837737Smckusick vap->va_fileid = ip->i_number; 18937737Smckusick vap->va_mode = ip->i_mode & ~IFMT; 19037737Smckusick vap->va_nlink = ip->i_nlink; 19137737Smckusick vap->va_uid = ip->i_uid; 19237737Smckusick vap->va_gid = ip->i_gid; 19337737Smckusick vap->va_rdev = (dev_t)ip->i_rdev; 19441312Smckusick #ifdef tahoe 19541312Smckusick vap->va_size = ip->i_size; 19641312Smckusick vap->va_size_rsv = 0; 19741312Smckusick #else 19840641Smckusick vap->va_qsize = ip->i_din.di_qsize; 19941312Smckusick #endif 20037737Smckusick vap->va_atime.tv_sec = ip->i_atime; 20138578Smckusick vap->va_atime.tv_usec = 0; 20237737Smckusick vap->va_mtime.tv_sec = ip->i_mtime; 20338578Smckusick vap->va_mtime.tv_usec = 0; 20437737Smckusick vap->va_ctime.tv_sec = ip->i_ctime; 20538578Smckusick vap->va_ctime.tv_usec = 0; 20638254Smckusick vap->va_flags = ip->i_flags; 20738254Smckusick vap->va_gen = ip->i_gen; 20837737Smckusick /* this doesn't belong here */ 20937737Smckusick if (vp->v_type == VBLK) 21037737Smckusick vap->va_blocksize = BLKDEV_IOSIZE; 21137737Smckusick else if (vp->v_type == VCHR) 21237737Smckusick vap->va_blocksize = MAXBSIZE; 2137142Smckusick else 21437737Smckusick vap->va_blocksize = ip->i_fs->fs_bsize; 21538657Smckusick vap->va_bytes = dbtob(ip->i_blocks); 21640641Smckusick vap->va_bytes_rsv = 0; 21737737Smckusick vap->va_type = vp->v_type; 21837737Smckusick return (0); 2196254Sroot } 2206254Sroot 2216254Sroot /* 22237737Smckusick * Set attribute vnode op. called from several syscalls 2236254Sroot */ 224*48039Smckusick ufs_setattr(vp, vap, cred, p) 22537737Smckusick register struct vnode *vp; 22637737Smckusick register struct vattr *vap; 22737737Smckusick register struct ucred *cred; 228*48039Smckusick struct proc *p; 2296254Sroot { 23037737Smckusick register struct inode *ip = VTOI(vp); 23137737Smckusick int error = 0; 2326254Sroot 23337737Smckusick /* 23437737Smckusick * Check for unsetable attributes. 23537737Smckusick */ 23637737Smckusick if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 23737737Smckusick (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 23837737Smckusick (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 23938254Smckusick ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 24037737Smckusick return (EINVAL); 24116540Ssam } 24237737Smckusick /* 24337737Smckusick * Go through the fields and update iff not VNOVAL. 24437737Smckusick */ 24537737Smckusick if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) 24647571Skarels if (error = chown1(vp, vap->va_uid, vap->va_gid, p)) 24737737Smckusick return (error); 24837737Smckusick if (vap->va_size != VNOVAL) { 24937737Smckusick if (vp->v_type == VDIR) 25037737Smckusick return (EISDIR); 25139674Smckusick if (error = itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */ 25237737Smckusick return (error); 25313878Ssam } 25437737Smckusick if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 25537773Smckusick if (cred->cr_uid != ip->i_uid && 25647571Skarels (error = suser(cred, &p->p_acflag))) 25737773Smckusick return (error); 25837737Smckusick if (vap->va_atime.tv_sec != VNOVAL) 25937737Smckusick ip->i_flag |= IACC; 26037737Smckusick if (vap->va_mtime.tv_sec != VNOVAL) 26137737Smckusick ip->i_flag |= IUPD; 26237737Smckusick ip->i_flag |= ICHG; 26337737Smckusick if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) 26437737Smckusick return (error); 2656254Sroot } 26637737Smckusick if (vap->va_mode != (u_short)VNOVAL) 26747571Skarels error = chmod1(vp, (int)vap->va_mode, p); 26838254Smckusick if (vap->va_flags != VNOVAL) { 26938254Smckusick if (cred->cr_uid != ip->i_uid && 27047571Skarels (error = suser(cred, &p->p_acflag))) 27138254Smckusick return (error); 27238254Smckusick if (cred->cr_uid == 0) { 27338254Smckusick ip->i_flags = vap->va_flags; 27438254Smckusick } else { 27538254Smckusick ip->i_flags &= 0xffff0000; 27638254Smckusick ip->i_flags |= (vap->va_flags & 0xffff); 27738254Smckusick } 27838254Smckusick ip->i_flag |= ICHG; 27938254Smckusick } 28037737Smckusick return (error); 2816254Sroot } 2826254Sroot 2836254Sroot /* 2849167Ssam * Change the mode on a file. 2859167Ssam * Inode must be locked before calling. 2869167Ssam */ 28747571Skarels chmod1(vp, mode, p) 28837737Smckusick register struct vnode *vp; 2897701Ssam register int mode; 29047571Skarels struct proc *p; 2917701Ssam { 29247571Skarels register struct ucred *cred = p->p_ucred; 29337737Smckusick register struct inode *ip = VTOI(vp); 29437773Smckusick int error; 2957868Sroot 29637773Smckusick if (cred->cr_uid != ip->i_uid && 29747571Skarels (error = suser(cred, &p->p_acflag))) 29837773Smckusick return (error); 29937737Smckusick if (cred->cr_uid) { 30046206Smckusick if (vp->v_type != VDIR && (mode & ISVTX)) 30145783Sbostic return (EFTYPE); 30246206Smckusick if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) 30345783Sbostic return (EPERM); 3047439Sroot } 30545783Sbostic ip->i_mode &= ~07777; 30637737Smckusick ip->i_mode |= mode & 07777; 3076254Sroot ip->i_flag |= ICHG; 30837737Smckusick if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) 30945722Smckusick (void) vnode_pager_uncache(vp); 31021015Smckusick return (0); 3115992Swnj } 3125992Swnj 3139167Ssam /* 3147701Ssam * Perform chown operation on inode ip; 3157701Ssam * inode must be locked prior to call. 3167701Ssam */ 31747571Skarels chown1(vp, uid, gid, p) 31837737Smckusick register struct vnode *vp; 31937737Smckusick uid_t uid; 32037737Smckusick gid_t gid; 32147571Skarels struct proc *p; 3227701Ssam { 32337737Smckusick register struct inode *ip = VTOI(vp); 32447571Skarels register struct ucred *cred = p->p_ucred; 32541312Smckusick uid_t ouid; 32641312Smckusick gid_t ogid; 32741312Smckusick int error = 0; 3287701Ssam #ifdef QUOTA 32941312Smckusick register int i; 33041312Smckusick long change; 33111811Ssam #endif 3327701Ssam 33337737Smckusick if (uid == (u_short)VNOVAL) 33411811Ssam uid = ip->i_uid; 33537737Smckusick if (gid == (u_short)VNOVAL) 33611811Ssam gid = ip->i_gid; 33736614Sbostic /* 33836614Sbostic * If we don't own the file, are trying to change the owner 33936614Sbostic * of the file, or are not a member of the target group, 34036614Sbostic * the caller must be superuser or the call fails. 34136614Sbostic */ 34237737Smckusick if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || 34337737Smckusick !groupmember((gid_t)gid, cred)) && 34447571Skarels (error = suser(cred, &p->p_acflag))) 34537737Smckusick return (error); 34641312Smckusick ouid = ip->i_uid; 34741312Smckusick ogid = ip->i_gid; 34811811Ssam #ifdef QUOTA 34941312Smckusick if (error = getinoquota(ip)) 35041312Smckusick return (error); 35141312Smckusick if (ouid == uid) { 35241312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 35341312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 35441312Smckusick } 35541312Smckusick if (ogid == gid) { 35641312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 35741312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 35841312Smckusick } 35941312Smckusick change = ip->i_blocks; 36041312Smckusick (void) chkdq(ip, -change, cred, CHOWN); 36141312Smckusick (void) chkiq(ip, -1, cred, CHOWN); 36241312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 36341312Smckusick dqrele(vp, ip->i_dquot[i]); 36441312Smckusick ip->i_dquot[i] = NODQUOT; 36541312Smckusick } 3667482Skre #endif 36711811Ssam ip->i_uid = uid; 36811811Ssam ip->i_gid = gid; 3697701Ssam #ifdef QUOTA 37041312Smckusick if ((error = getinoquota(ip)) == 0) { 37141312Smckusick if (ouid == uid) { 37241312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 37341312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 37441312Smckusick } 37541312Smckusick if (ogid == gid) { 37641312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 37741312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 37841312Smckusick } 37941312Smckusick if ((error = chkdq(ip, change, cred, CHOWN)) == 0) { 38041312Smckusick if ((error = chkiq(ip, 1, cred, CHOWN)) == 0) 38141927Smckusick goto good; 38241312Smckusick else 38341312Smckusick (void) chkdq(ip, -change, cred, CHOWN|FORCE); 38441312Smckusick } 38541312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 38641312Smckusick dqrele(vp, ip->i_dquot[i]); 38741312Smckusick ip->i_dquot[i] = NODQUOT; 38841312Smckusick } 38941312Smckusick } 39041312Smckusick ip->i_uid = ouid; 39141312Smckusick ip->i_gid = ogid; 39241312Smckusick if (getinoquota(ip) == 0) { 39341312Smckusick if (ouid == uid) { 39441312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 39541312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 39641312Smckusick } 39741312Smckusick if (ogid == gid) { 39841312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 39941312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 40041312Smckusick } 40141927Smckusick (void) chkdq(ip, change, cred, FORCE|CHOWN); 40241927Smckusick (void) chkiq(ip, 1, cred, FORCE|CHOWN); 40342440Smckusick (void) getinoquota(ip); 40441312Smckusick } 40542440Smckusick return (error); 40641927Smckusick good: 40742440Smckusick if (getinoquota(ip)) 40842440Smckusick panic("chown: lost quota"); 40942440Smckusick #endif /* QUOTA */ 41041312Smckusick if (ouid != uid || ogid != gid) 41141312Smckusick ip->i_flag |= ICHG; 41241312Smckusick if (ouid != uid && cred->cr_uid != 0) 41341312Smckusick ip->i_mode &= ~ISUID; 41441312Smckusick if (ogid != gid && cred->cr_uid != 0) 41541312Smckusick ip->i_mode &= ~ISGID; 41612646Ssam return (0); 41737Sbill } 41837Sbill 41939608Smckusick /* 42039608Smckusick * Vnode op for reading. 42139608Smckusick */ 42237737Smckusick /* ARGSUSED */ 42339608Smckusick ufs_read(vp, uio, ioflag, cred) 42439608Smckusick struct vnode *vp; 42539608Smckusick register struct uio *uio; 42639608Smckusick int ioflag; 42739608Smckusick struct ucred *cred; 42839608Smckusick { 42939608Smckusick register struct inode *ip = VTOI(vp); 43039608Smckusick register struct fs *fs; 43139608Smckusick struct buf *bp; 43239608Smckusick daddr_t lbn, bn, rablock; 43339896Smckusick int size, diff, error = 0; 43439608Smckusick long n, on, type; 43539608Smckusick 436*48039Smckusick #ifdef DIAGNOSTIC 43739608Smckusick if (uio->uio_rw != UIO_READ) 43839608Smckusick panic("ufs_read mode"); 43939608Smckusick type = ip->i_mode & IFMT; 44039608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 44139608Smckusick panic("ufs_read type"); 442*48039Smckusick #endif 44339608Smckusick if (uio->uio_resid == 0) 44439608Smckusick return (0); 44539608Smckusick if (uio->uio_offset < 0) 44639608Smckusick return (EINVAL); 44739608Smckusick ip->i_flag |= IACC; 44839608Smckusick fs = ip->i_fs; 44939608Smckusick do { 45039608Smckusick lbn = lblkno(fs, uio->uio_offset); 45139608Smckusick on = blkoff(fs, uio->uio_offset); 45239608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 45339608Smckusick diff = ip->i_size - uio->uio_offset; 45439608Smckusick if (diff <= 0) 45539608Smckusick return (0); 45639608Smckusick if (diff < n) 45739608Smckusick n = diff; 45839608Smckusick size = blksize(fs, ip, lbn); 45939674Smckusick rablock = lbn + 1; 46039896Smckusick if (vp->v_lastr + 1 == lbn && 46139896Smckusick lblktosize(fs, rablock) < ip->i_size) 46239896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 46339896Smckusick blksize(fs, ip, rablock), NOCRED, &bp); 46439608Smckusick else 46539674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 46639815Smckusick vp->v_lastr = lbn; 46739608Smckusick n = MIN(n, size - bp->b_resid); 46839608Smckusick if (error) { 46939608Smckusick brelse(bp); 47039608Smckusick return (error); 47139608Smckusick } 47239608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 47339608Smckusick if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size) 47439608Smckusick bp->b_flags |= B_AGE; 47539608Smckusick brelse(bp); 47639608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 47739608Smckusick return (error); 47839608Smckusick } 47939608Smckusick 48039608Smckusick /* 48139608Smckusick * Vnode op for writing. 48239608Smckusick */ 48339608Smckusick ufs_write(vp, uio, ioflag, cred) 48439608Smckusick register struct vnode *vp; 48539608Smckusick struct uio *uio; 48639608Smckusick int ioflag; 48739608Smckusick struct ucred *cred; 48839608Smckusick { 489*48039Smckusick struct proc *p = uio->uio_procp; 49039608Smckusick register struct inode *ip = VTOI(vp); 49139608Smckusick register struct fs *fs; 49239608Smckusick struct buf *bp; 49339608Smckusick daddr_t lbn, bn; 49439608Smckusick u_long osize; 49545722Smckusick int n, on, flags; 49645722Smckusick int size, resid, error = 0; 49739608Smckusick 498*48039Smckusick #ifdef DIAGNOSTIC 49939608Smckusick if (uio->uio_rw != UIO_WRITE) 50039608Smckusick panic("ufs_write mode"); 501*48039Smckusick #endif 50239608Smckusick switch (vp->v_type) { 50339608Smckusick case VREG: 50439608Smckusick if (ioflag & IO_APPEND) 50539608Smckusick uio->uio_offset = ip->i_size; 50639608Smckusick /* fall through */ 50739608Smckusick case VLNK: 50839608Smckusick break; 50939608Smckusick 51039608Smckusick case VDIR: 51139608Smckusick if ((ioflag & IO_SYNC) == 0) 51239608Smckusick panic("ufs_write nonsync dir write"); 51339608Smckusick break; 51439608Smckusick 51539608Smckusick default: 51639608Smckusick panic("ufs_write type"); 51739608Smckusick } 51839608Smckusick if (uio->uio_offset < 0) 51939608Smckusick return (EINVAL); 52039608Smckusick if (uio->uio_resid == 0) 52139608Smckusick return (0); 52239608Smckusick /* 52339608Smckusick * Maybe this should be above the vnode op call, but so long as 52439608Smckusick * file servers have no limits, i don't think it matters 52539608Smckusick */ 52639608Smckusick if (vp->v_type == VREG && 52739608Smckusick uio->uio_offset + uio->uio_resid > 52847571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 52947571Skarels psignal(p, SIGXFSZ); 53039608Smckusick return (EFBIG); 53139608Smckusick } 53239608Smckusick resid = uio->uio_resid; 53339608Smckusick osize = ip->i_size; 53439608Smckusick fs = ip->i_fs; 53539674Smckusick flags = 0; 53639674Smckusick if (ioflag & IO_SYNC) 53739674Smckusick flags = B_SYNC; 53839608Smckusick do { 53939608Smckusick lbn = lblkno(fs, uio->uio_offset); 54039608Smckusick on = blkoff(fs, uio->uio_offset); 54139608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 54239608Smckusick if (n < fs->fs_bsize) 54339674Smckusick flags |= B_CLRBUF; 54439608Smckusick else 54539674Smckusick flags &= ~B_CLRBUF; 54639674Smckusick if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) 54739608Smckusick break; 54839674Smckusick bn = bp->b_blkno; 54945722Smckusick if (uio->uio_offset + n > ip->i_size) { 55039608Smckusick ip->i_size = uio->uio_offset + n; 55145722Smckusick vnode_pager_setsize(vp, ip->i_size); 55245722Smckusick } 55339608Smckusick size = blksize(fs, ip, lbn); 55445722Smckusick (void) vnode_pager_uncache(vp); 55539608Smckusick n = MIN(n, size - bp->b_resid); 55639608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 55739608Smckusick if (ioflag & IO_SYNC) 55839608Smckusick (void) bwrite(bp); 55939608Smckusick else if (n + on == fs->fs_bsize) { 56039608Smckusick bp->b_flags |= B_AGE; 56139608Smckusick bawrite(bp); 56239608Smckusick } else 56339608Smckusick bdwrite(bp); 56439608Smckusick ip->i_flag |= IUPD|ICHG; 56539608Smckusick if (cred->cr_uid != 0) 56639608Smckusick ip->i_mode &= ~(ISUID|ISGID); 56739608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 56839608Smckusick if (error && (ioflag & IO_UNIT)) { 56939674Smckusick (void) itrunc(ip, osize, ioflag & IO_SYNC); 57039608Smckusick uio->uio_offset -= resid - uio->uio_resid; 57139608Smckusick uio->uio_resid = resid; 57239608Smckusick } 57342493Smckusick if (!error && (ioflag & IO_SYNC)) 57442493Smckusick error = iupdat(ip, &time, &time, 1); 57539608Smckusick return (error); 57639608Smckusick } 57739608Smckusick 57839608Smckusick /* ARGSUSED */ 579*48039Smckusick ufs_ioctl(vp, com, data, fflag, cred, p) 58037737Smckusick struct vnode *vp; 58137737Smckusick int com; 58237737Smckusick caddr_t data; 58337737Smckusick int fflag; 58437737Smckusick struct ucred *cred; 585*48039Smckusick struct proc *p; 58611811Ssam { 58711811Ssam 58837737Smckusick return (ENOTTY); 58911811Ssam } 59011811Ssam 59137737Smckusick /* ARGSUSED */ 592*48039Smckusick ufs_select(vp, which, fflags, cred, p) 59337737Smckusick struct vnode *vp; 59440290Smckusick int which, fflags; 59537737Smckusick struct ucred *cred; 596*48039Smckusick struct proc *p; 59737737Smckusick { 59837737Smckusick 599*48039Smckusick /* 600*48039Smckusick * We should really check to see if I/O is possible. 601*48039Smckusick */ 602*48039Smckusick return (1); 60337737Smckusick } 60437737Smckusick 6059167Ssam /* 60637737Smckusick * Mmap a file 60737737Smckusick * 60837737Smckusick * NB Currently unsupported. 6099167Ssam */ 61037737Smckusick /* ARGSUSED */ 611*48039Smckusick ufs_mmap(vp, fflags, cred, p) 61237737Smckusick struct vnode *vp; 61337737Smckusick int fflags; 61437737Smckusick struct ucred *cred; 615*48039Smckusick struct proc *p; 61637Sbill { 61737Sbill 61837737Smckusick return (EINVAL); 61937Sbill } 6207535Sroot 6219167Ssam /* 62237737Smckusick * Synch an open file. 6239167Ssam */ 62437737Smckusick /* ARGSUSED */ 625*48039Smckusick ufs_fsync(vp, fflags, cred, waitfor, p) 62637737Smckusick struct vnode *vp; 62737737Smckusick int fflags; 62837737Smckusick struct ucred *cred; 62939597Smckusick int waitfor; 630*48039Smckusick struct proc *p; 6317701Ssam { 63239597Smckusick struct inode *ip = VTOI(vp); 6337701Ssam 634*48039Smckusick if (fflags & FWRITE) 63537737Smckusick ip->i_flag |= ICHG; 63639674Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 63739674Smckusick return (iupdat(ip, &time, &time, waitfor == MNT_WAIT)); 6387701Ssam } 6397701Ssam 6409167Ssam /* 64137737Smckusick * Seek on a file 64237737Smckusick * 64337737Smckusick * Nothing to do, so just return. 6449167Ssam */ 64537737Smckusick /* ARGSUSED */ 64637737Smckusick ufs_seek(vp, oldoff, newoff, cred) 64737737Smckusick struct vnode *vp; 64837737Smckusick off_t oldoff, newoff; 64937737Smckusick struct ucred *cred; 6507701Ssam { 6517701Ssam 65237737Smckusick return (0); 65337737Smckusick } 65437737Smckusick 65537737Smckusick /* 65637737Smckusick * ufs remove 65737737Smckusick * Hard to avoid races here, especially 65837737Smckusick * in unlinking directories. 65937737Smckusick */ 660*48039Smckusick ufs_remove(ndp, p) 66137737Smckusick struct nameidata *ndp; 662*48039Smckusick struct proc *p; 66337737Smckusick { 66437737Smckusick register struct inode *ip, *dp; 66537737Smckusick int error; 66637737Smckusick 66737737Smckusick ip = VTOI(ndp->ni_vp); 66837737Smckusick dp = VTOI(ndp->ni_dvp); 66937737Smckusick error = dirremove(ndp); 67037737Smckusick if (!error) { 67137737Smckusick ip->i_nlink--; 67237737Smckusick ip->i_flag |= ICHG; 6737701Ssam } 67437737Smckusick if (dp == ip) 67537737Smckusick vrele(ITOV(ip)); 67637737Smckusick else 67737737Smckusick iput(ip); 67837737Smckusick iput(dp); 67937737Smckusick return (error); 6807701Ssam } 6817701Ssam 6829167Ssam /* 68337737Smckusick * link vnode call 6849167Ssam */ 685*48039Smckusick ufs_link(vp, ndp, p) 68637737Smckusick register struct vnode *vp; 68737737Smckusick register struct nameidata *ndp; 688*48039Smckusick struct proc *p; 6899167Ssam { 69037737Smckusick register struct inode *ip = VTOI(vp); 69137737Smckusick int error; 6929167Ssam 69346251Smckusick if ((unsigned short)ip->i_nlink >= LINK_MAX) 69446251Smckusick return (EMLINK); 69537737Smckusick if (ndp->ni_dvp != vp) 69637737Smckusick ILOCK(ip); 69737737Smckusick ip->i_nlink++; 69837737Smckusick ip->i_flag |= ICHG; 69937737Smckusick error = iupdat(ip, &time, &time, 1); 70037737Smckusick if (!error) 70137737Smckusick error = direnter(ip, ndp); 70237737Smckusick if (ndp->ni_dvp != vp) 70337737Smckusick IUNLOCK(ip); 70447219Smckusick vput(ndp->ni_dvp); 70537737Smckusick if (error) { 70637737Smckusick ip->i_nlink--; 70730598Smckusick ip->i_flag |= ICHG; 70837737Smckusick } 70937737Smckusick return (error); 7109167Ssam } 7119167Ssam 7129167Ssam /* 7139167Ssam * Rename system call. 7149167Ssam * rename("foo", "bar"); 7159167Ssam * is essentially 7169167Ssam * unlink("bar"); 7179167Ssam * link("foo", "bar"); 7189167Ssam * unlink("foo"); 7199167Ssam * but ``atomically''. Can't do full commit without saving state in the 7209167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7219167Ssam * always guarantee the target exists. 7229167Ssam * 7239167Ssam * Basic algorithm is: 7249167Ssam * 7259167Ssam * 1) Bump link count on source while we're linking it to the 72637737Smckusick * target. This also ensure the inode won't be deleted out 72716776Smckusick * from underneath us while we work (it may be truncated by 72816776Smckusick * a concurrent `trunc' or `open' for creation). 7299167Ssam * 2) Link source to destination. If destination already exists, 7309167Ssam * delete it first. 73116776Smckusick * 3) Unlink source reference to inode if still around. If a 73216776Smckusick * directory was moved and the parent of the destination 7339167Ssam * is different from the source, patch the ".." entry in the 7349167Ssam * directory. 7359167Ssam */ 736*48039Smckusick ufs_rename(fndp, tndp, p) 73737737Smckusick register struct nameidata *fndp, *tndp; 738*48039Smckusick struct proc *p; 7397701Ssam { 7409167Ssam register struct inode *ip, *xp, *dp; 74116776Smckusick struct dirtemplate dirbuf; 74216776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 74310051Ssam int error = 0; 7447701Ssam 74537737Smckusick dp = VTOI(fndp->ni_dvp); 74637737Smckusick ip = VTOI(fndp->ni_vp); 74737737Smckusick ILOCK(ip); 7489167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 74937737Smckusick register struct direct *d = &fndp->ni_dent; 7509167Ssam 7519167Ssam /* 75211641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 7539167Ssam */ 75437737Smckusick if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip || 75537737Smckusick fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { 75642466Smckusick VOP_ABORTOP(tndp); 75742466Smckusick vput(tndp->ni_dvp); 75842466Smckusick if (tndp->ni_vp) 75942466Smckusick vput(tndp->ni_vp); 76042466Smckusick VOP_ABORTOP(fndp); 76142466Smckusick vrele(fndp->ni_dvp); 76242466Smckusick vput(fndp->ni_vp); 76337737Smckusick return (EINVAL); 7649167Ssam } 76516776Smckusick ip->i_flag |= IRENAME; 7669167Ssam oldparent = dp->i_number; 7679167Ssam doingdirectory++; 7689167Ssam } 76937737Smckusick vrele(fndp->ni_dvp); 7709167Ssam 7719167Ssam /* 7729167Ssam * 1) Bump link count while we're moving stuff 7739167Ssam * around. If we crash somewhere before 7749167Ssam * completing our work, the link count 7759167Ssam * may be wrong, but correctable. 7769167Ssam */ 7779167Ssam ip->i_nlink++; 7789167Ssam ip->i_flag |= ICHG; 77937737Smckusick error = iupdat(ip, &time, &time, 1); 78016664Smckusick IUNLOCK(ip); 7819167Ssam 7829167Ssam /* 7839167Ssam * When the target exists, both the directory 78437737Smckusick * and target vnodes are returned locked. 7859167Ssam */ 78637737Smckusick dp = VTOI(tndp->ni_dvp); 78737737Smckusick xp = NULL; 78837737Smckusick if (tndp->ni_vp) 78937737Smckusick xp = VTOI(tndp->ni_vp); 7909167Ssam /* 79111641Ssam * If ".." must be changed (ie the directory gets a new 79212816Smckusick * parent) then the source directory must not be in the 79312816Smckusick * directory heirarchy above the target, as this would 79412816Smckusick * orphan everything below the source directory. Also 79512816Smckusick * the user must have write permission in the source so 79612816Smckusick * as to be able to change "..". We must repeat the call 79712816Smckusick * to namei, as the parent directory is unlocked by the 79812816Smckusick * call to checkpath(). 79911641Ssam */ 80016776Smckusick if (oldparent != dp->i_number) 80116776Smckusick newparent = dp->i_number; 80216776Smckusick if (doingdirectory && newparent) { 80341466Smckusick VOP_LOCK(fndp->ni_vp); 804*48039Smckusick error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred, p); 80541466Smckusick VOP_UNLOCK(fndp->ni_vp); 80641466Smckusick if (error) 80712816Smckusick goto bad; 80846511Smckusick tndp->ni_nameiop &= ~(MODMASK | OPMASK); 80946511Smckusick tndp->ni_nameiop |= RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 81012816Smckusick do { 81137737Smckusick dp = VTOI(tndp->ni_dvp); 81212816Smckusick if (xp != NULL) 81338069Smckusick iput(xp); 81437737Smckusick if (error = checkpath(ip, dp, tndp->ni_cred)) 81512816Smckusick goto out; 81647571Skarels if (error = namei(tndp, p)) 81712816Smckusick goto out; 81837737Smckusick xp = NULL; 81937737Smckusick if (tndp->ni_vp) 82037737Smckusick xp = VTOI(tndp->ni_vp); 82137737Smckusick } while (dp != VTOI(tndp->ni_dvp)); 82212816Smckusick } 82311641Ssam /* 8249167Ssam * 2) If target doesn't exist, link the target 8259167Ssam * to the source and unlink the source. 8269167Ssam * Otherwise, rewrite the target directory 8279167Ssam * entry to reference the source inode and 8289167Ssam * expunge the original entry's existence. 8299167Ssam */ 8309167Ssam if (xp == NULL) { 83137737Smckusick if (dp->i_dev != ip->i_dev) 83237737Smckusick panic("rename: EXDEV"); 8339167Ssam /* 83416776Smckusick * Account for ".." in new directory. 83516776Smckusick * When source and destination have the same 83616776Smckusick * parent we don't fool with the link count. 8379167Ssam */ 83816776Smckusick if (doingdirectory && newparent) { 83946251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 84046251Smckusick error = EMLINK; 84146251Smckusick goto bad; 84246251Smckusick } 8439167Ssam dp->i_nlink++; 8449167Ssam dp->i_flag |= ICHG; 84546251Smckusick if (error = iupdat(dp, &time, &time, 1)) 84646251Smckusick goto bad; 8479167Ssam } 84847219Smckusick if (error = direnter(ip, tndp)) { 84947219Smckusick if (doingdirectory && newparent) { 85047219Smckusick dp->i_nlink--; 85147219Smckusick dp->i_flag |= ICHG; 85247219Smckusick (void) iupdat(dp, &time, &time, 1); 85347219Smckusick } 85447219Smckusick goto bad; 85547219Smckusick } 85647234Smckusick iput(dp); 8579167Ssam } else { 85837737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 85937737Smckusick panic("rename: EXDEV"); 8609167Ssam /* 86110590Ssam * Short circuit rename(foo, foo). 86210590Ssam */ 86310590Ssam if (xp->i_number == ip->i_number) 86437737Smckusick panic("rename: same file"); 86510590Ssam /* 86624433Sbloom * If the parent directory is "sticky", then the user must 86724433Sbloom * own the parent directory, or the destination of the rename, 86824433Sbloom * otherwise the destination may not be changed (except by 86924433Sbloom * root). This implements append-only directories. 87024433Sbloom */ 87137737Smckusick if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && 87237737Smckusick tndp->ni_cred->cr_uid != dp->i_uid && 87337737Smckusick xp->i_uid != tndp->ni_cred->cr_uid) { 87424433Sbloom error = EPERM; 87524433Sbloom goto bad; 87624433Sbloom } 87724433Sbloom /* 87810051Ssam * Target must be empty if a directory 87910051Ssam * and have no links to it. 8809167Ssam * Also, insure source and target are 8819167Ssam * compatible (both directories, or both 8829167Ssam * not directories). 8839167Ssam */ 8849167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 88537737Smckusick if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 88637737Smckusick xp->i_nlink > 2) { 88710051Ssam error = ENOTEMPTY; 8889167Ssam goto bad; 8899167Ssam } 8909167Ssam if (!doingdirectory) { 89110051Ssam error = ENOTDIR; 8929167Ssam goto bad; 8939167Ssam } 89437737Smckusick cache_purge(ITOV(dp)); 8959167Ssam } else if (doingdirectory) { 89610051Ssam error = EISDIR; 8979167Ssam goto bad; 8989167Ssam } 89937737Smckusick if (error = dirrewrite(dp, ip, tndp)) 90037737Smckusick goto bad; 90145354Smckusick /* 90245354Smckusick * If the target directory is in the same 90345354Smckusick * directory as the source directory, 90445354Smckusick * decrement the link count on the parent 90545354Smckusick * of the target directory. 90645354Smckusick */ 90745354Smckusick if (doingdirectory && !newparent) { 90845354Smckusick dp->i_nlink--; 90945354Smckusick dp->i_flag |= ICHG; 91045354Smckusick } 91137737Smckusick vput(ITOV(dp)); 9129167Ssam /* 91310051Ssam * Adjust the link count of the target to 91410051Ssam * reflect the dirrewrite above. If this is 91510051Ssam * a directory it is empty and there are 91610051Ssam * no links to it, so we can squash the inode and 91710051Ssam * any space associated with it. We disallowed 91810051Ssam * renaming over top of a directory with links to 91916776Smckusick * it above, as the remaining link would point to 92016776Smckusick * a directory without "." or ".." entries. 9219167Ssam */ 92210051Ssam xp->i_nlink--; 9239167Ssam if (doingdirectory) { 92410051Ssam if (--xp->i_nlink != 0) 92510051Ssam panic("rename: linked directory"); 92639674Smckusick error = itrunc(xp, (u_long)0, IO_SYNC); 92710051Ssam } 9289167Ssam xp->i_flag |= ICHG; 92938398Smckusick iput(xp); 93010246Ssam xp = NULL; 9319167Ssam } 9329167Ssam 9339167Ssam /* 9349167Ssam * 3) Unlink the source. 9359167Ssam */ 93646511Smckusick fndp->ni_nameiop &= ~(MODMASK | OPMASK); 93746511Smckusick fndp->ni_nameiop |= DELETE | LOCKPARENT | LOCKLEAF; 93847571Skarels (void)namei(fndp, p); 93937737Smckusick if (fndp->ni_vp != NULL) { 94037737Smckusick xp = VTOI(fndp->ni_vp); 94137737Smckusick dp = VTOI(fndp->ni_dvp); 94237737Smckusick } else { 94346250Smckusick /* 94446250Smckusick * From name has disappeared. 94546250Smckusick */ 94646250Smckusick if (doingdirectory) 94746250Smckusick panic("rename: lost dir entry"); 94846250Smckusick vrele(ITOV(ip)); 94946250Smckusick return (0); 95037737Smckusick } 9519167Ssam /* 95237737Smckusick * Ensure that the directory entry still exists and has not 95316776Smckusick * changed while the new name has been entered. If the source is 95416776Smckusick * a file then the entry may have been unlinked or renamed. In 95516776Smckusick * either case there is no further work to be done. If the source 95616776Smckusick * is a directory then it cannot have been rmdir'ed; its link 95716776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 95837737Smckusick * The IRENAME flag ensures that it cannot be moved by another 95916776Smckusick * rename. 9609167Ssam */ 96117758Smckusick if (xp != ip) { 96216776Smckusick if (doingdirectory) 96317758Smckusick panic("rename: lost dir entry"); 96416776Smckusick } else { 9659167Ssam /* 96616776Smckusick * If the source is a directory with a 96716776Smckusick * new parent, the link count of the old 96816776Smckusick * parent directory must be decremented 96916776Smckusick * and ".." set to point to the new parent. 9709167Ssam */ 97116776Smckusick if (doingdirectory && newparent) { 9729167Ssam dp->i_nlink--; 9739167Ssam dp->i_flag |= ICHG; 97439597Smckusick error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, 97537737Smckusick sizeof (struct dirtemplate), (off_t)0, 97639597Smckusick UIO_SYSSPACE, IO_NODELOCKED, 977*48039Smckusick tndp->ni_cred, (int *)0, (struct proc *)0); 97816776Smckusick if (error == 0) { 97916776Smckusick if (dirbuf.dotdot_namlen != 2 || 98016776Smckusick dirbuf.dotdot_name[0] != '.' || 98116776Smckusick dirbuf.dotdot_name[1] != '.') { 98239610Smckusick dirbad(xp, 12, "rename: mangled dir"); 98316776Smckusick } else { 98416776Smckusick dirbuf.dotdot_ino = newparent; 98539597Smckusick (void) vn_rdwr(UIO_WRITE, ITOV(xp), 98616776Smckusick (caddr_t)&dirbuf, 98716776Smckusick sizeof (struct dirtemplate), 98837740Smckusick (off_t)0, UIO_SYSSPACE, 98939597Smckusick IO_NODELOCKED|IO_SYNC, 990*48039Smckusick tndp->ni_cred, (int *)0, 991*48039Smckusick (struct proc *)0); 99237737Smckusick cache_purge(ITOV(dp)); 99316776Smckusick } 99416776Smckusick } 9959167Ssam } 99637737Smckusick error = dirremove(fndp); 99737737Smckusick if (!error) { 99816776Smckusick xp->i_nlink--; 99916776Smckusick xp->i_flag |= ICHG; 10009167Ssam } 100116776Smckusick xp->i_flag &= ~IRENAME; 10029167Ssam } 10039167Ssam if (dp) 100437737Smckusick vput(ITOV(dp)); 100516776Smckusick if (xp) 100637737Smckusick vput(ITOV(xp)); 100737737Smckusick vrele(ITOV(ip)); 100837737Smckusick return (error); 10099167Ssam 10109167Ssam bad: 10119167Ssam if (xp) 101237737Smckusick vput(ITOV(xp)); 101337737Smckusick vput(ITOV(dp)); 10149167Ssam out: 10159167Ssam ip->i_nlink--; 10169167Ssam ip->i_flag |= ICHG; 101737737Smckusick vrele(ITOV(ip)); 101837737Smckusick return (error); 10197701Ssam } 10207701Ssam 10217535Sroot /* 102212756Ssam * A virgin directory (no blushing please). 102312756Ssam */ 102412756Ssam struct dirtemplate mastertemplate = { 102512756Ssam 0, 12, 1, ".", 102612756Ssam 0, DIRBLKSIZ - 12, 2, ".." 102712756Ssam }; 102812756Ssam 102912756Ssam /* 103012756Ssam * Mkdir system call 103112756Ssam */ 1032*48039Smckusick ufs_mkdir(ndp, vap, p) 103337737Smckusick struct nameidata *ndp; 103437737Smckusick struct vattr *vap; 1035*48039Smckusick struct proc *p; 103612756Ssam { 103712756Ssam register struct inode *ip, *dp; 103837737Smckusick struct inode *tip; 103937737Smckusick struct vnode *dvp; 104012756Ssam struct dirtemplate dirtemplate; 104137737Smckusick int error; 104237737Smckusick int dmode; 104312756Ssam 104437737Smckusick dvp = ndp->ni_dvp; 104537737Smckusick dp = VTOI(dvp); 104646251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 104746251Smckusick iput(dp); 104846251Smckusick return (EMLINK); 104946251Smckusick } 105037737Smckusick dmode = vap->va_mode&0777; 105137737Smckusick dmode |= IFDIR; 105212756Ssam /* 105312756Ssam * Must simulate part of maknode here 105412756Ssam * in order to acquire the inode, but 105512756Ssam * not have it entered in the parent 105612756Ssam * directory. The entry is made later 105712756Ssam * after writing "." and ".." entries out. 105812756Ssam */ 105941312Smckusick if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { 106012756Ssam iput(dp); 106137737Smckusick return (error); 106212756Ssam } 106337737Smckusick ip = tip; 106441312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 106541312Smckusick ip->i_gid = dp->i_gid; 106612756Ssam #ifdef QUOTA 106741312Smckusick if ((error = getinoquota(ip)) || 106841312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 106941312Smckusick ifree(ip, ip->i_number, dmode); 107041312Smckusick iput(ip); 107141312Smckusick iput(dp); 107241312Smckusick return (error); 107341312Smckusick } 107412756Ssam #endif 107512756Ssam ip->i_flag |= IACC|IUPD|ICHG; 107637737Smckusick ip->i_mode = dmode; 107737737Smckusick ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ 107812756Ssam ip->i_nlink = 2; 107937737Smckusick error = iupdat(ip, &time, &time, 1); 108012756Ssam 108112756Ssam /* 108212756Ssam * Bump link count in parent directory 108312756Ssam * to reflect work done below. Should 108412756Ssam * be done before reference is created 108512756Ssam * so reparation is possible if we crash. 108612756Ssam */ 108712756Ssam dp->i_nlink++; 108812756Ssam dp->i_flag |= ICHG; 108947219Smckusick if (error = iupdat(dp, &time, &time, 1)) 109047219Smckusick goto bad; 109112756Ssam 109212756Ssam /* 109312756Ssam * Initialize directory with "." 109412756Ssam * and ".." from static template. 109512756Ssam */ 109612756Ssam dirtemplate = mastertemplate; 109712756Ssam dirtemplate.dot_ino = ip->i_number; 109812756Ssam dirtemplate.dotdot_ino = dp->i_number; 109939597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, 1100*48039Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 1101*48039Smckusick IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0, (struct proc *)0); 110237737Smckusick if (error) { 110312756Ssam dp->i_nlink--; 110412756Ssam dp->i_flag |= ICHG; 110512756Ssam goto bad; 110612756Ssam } 110743288Smckusick if (DIRBLKSIZ > dp->i_fs->fs_fsize) { 110837737Smckusick panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ 110943288Smckusick } else { 111018103Smckusick ip->i_size = DIRBLKSIZ; 111143288Smckusick ip->i_flag |= ICHG; 111243288Smckusick } 111312756Ssam /* 111412756Ssam * Directory all set up, now 111512756Ssam * install the entry for it in 111612756Ssam * the parent directory. 111712756Ssam */ 111847219Smckusick if (error = direnter(ip, ndp)) { 111947657Smckusick dp->i_nlink--; 112047657Smckusick dp->i_flag |= ICHG; 112112756Ssam } 112212756Ssam bad: 112312756Ssam /* 112412756Ssam * No need to do an explicit itrunc here, 112537737Smckusick * vrele will do this for us because we set 112612756Ssam * the link count to 0. 112712756Ssam */ 112837737Smckusick if (error) { 112912756Ssam ip->i_nlink = 0; 113012756Ssam ip->i_flag |= ICHG; 113138144Smckusick iput(ip); 113238144Smckusick } else 113338144Smckusick ndp->ni_vp = ITOV(ip); 113447219Smckusick iput(dp); 113537737Smckusick return (error); 113612756Ssam } 113712756Ssam 113812756Ssam /* 113912756Ssam * Rmdir system call. 114012756Ssam */ 1141*48039Smckusick ufs_rmdir(ndp, p) 114237737Smckusick register struct nameidata *ndp; 1143*48039Smckusick struct proc *p; 114412756Ssam { 114512756Ssam register struct inode *ip, *dp; 114637737Smckusick int error = 0; 114712756Ssam 114837737Smckusick ip = VTOI(ndp->ni_vp); 114937737Smckusick dp = VTOI(ndp->ni_dvp); 115012756Ssam /* 115112756Ssam * No rmdir "." please. 115212756Ssam */ 115312756Ssam if (dp == ip) { 115437737Smckusick vrele(ITOV(dp)); 115512756Ssam iput(ip); 115637737Smckusick return (EINVAL); 115712756Ssam } 115812756Ssam /* 115912756Ssam * Verify the directory is empty (and valid). 116012756Ssam * (Rmdir ".." won't be valid since 116112756Ssam * ".." will contain a reference to 116212756Ssam * the current directory and thus be 116312756Ssam * non-empty.) 116412756Ssam */ 116537737Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { 116637737Smckusick error = ENOTEMPTY; 116712756Ssam goto out; 116812756Ssam } 116912756Ssam /* 117012756Ssam * Delete reference to directory before purging 117112756Ssam * inode. If we crash in between, the directory 117212756Ssam * will be reattached to lost+found, 117312756Ssam */ 117437737Smckusick if (error = dirremove(ndp)) 117512756Ssam goto out; 117612756Ssam dp->i_nlink--; 117712756Ssam dp->i_flag |= ICHG; 117837737Smckusick cache_purge(ITOV(dp)); 117912756Ssam iput(dp); 118037737Smckusick ndp->ni_dvp = NULL; 118112756Ssam /* 118212756Ssam * Truncate inode. The only stuff left 118312756Ssam * in the directory is "." and "..". The 118412756Ssam * "." reference is inconsequential since 118512756Ssam * we're quashing it. The ".." reference 118612756Ssam * has already been adjusted above. We've 118712756Ssam * removed the "." reference and the reference 118812756Ssam * in the parent directory, but there may be 118912756Ssam * other hard links so decrement by 2 and 119012756Ssam * worry about them later. 119112756Ssam */ 119212756Ssam ip->i_nlink -= 2; 119339674Smckusick error = itrunc(ip, (u_long)0, IO_SYNC); 119437737Smckusick cache_purge(ITOV(ip)); 119512756Ssam out: 119637737Smckusick if (ndp->ni_dvp) 119712756Ssam iput(dp); 119812756Ssam iput(ip); 119937737Smckusick return (error); 120012756Ssam } 120112756Ssam 120237737Smckusick /* 120337737Smckusick * symlink -- make a symbolic link 120437737Smckusick */ 1205*48039Smckusick ufs_symlink(ndp, vap, target, p) 120637737Smckusick struct nameidata *ndp; 120737737Smckusick struct vattr *vap; 120837737Smckusick char *target; 1209*48039Smckusick struct proc *p; 121012756Ssam { 121137737Smckusick struct inode *ip; 121237737Smckusick int error; 121312756Ssam 121437737Smckusick error = maknode(IFLNK | vap->va_mode, ndp, &ip); 121537737Smckusick if (error) 121637737Smckusick return (error); 121739597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, 1218*48039Smckusick UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0, 1219*48039Smckusick (struct proc *)0); 122037737Smckusick iput(ip); 122137737Smckusick return (error); 122237737Smckusick } 122337737Smckusick 122437737Smckusick /* 122537737Smckusick * Vnode op for read and write 122637737Smckusick */ 122740345Smckusick ufs_readdir(vp, uio, cred, eofflagp) 122837737Smckusick struct vnode *vp; 122937737Smckusick register struct uio *uio; 123037737Smckusick struct ucred *cred; 123140345Smckusick int *eofflagp; 123237737Smckusick { 123339597Smckusick int count, lost, error; 123437737Smckusick 123537737Smckusick count = uio->uio_resid; 123637737Smckusick count &= ~(DIRBLKSIZ - 1); 123739597Smckusick lost = uio->uio_resid - count; 123839597Smckusick if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) 123937737Smckusick return (EINVAL); 124037737Smckusick uio->uio_resid = count; 124137737Smckusick uio->uio_iov->iov_len = count; 124239597Smckusick error = ufs_read(vp, uio, 0, cred); 124339597Smckusick uio->uio_resid += lost; 124440345Smckusick if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) 124540345Smckusick *eofflagp = 1; 124640345Smckusick else 124740345Smckusick *eofflagp = 0; 124837737Smckusick return (error); 124937737Smckusick } 125037737Smckusick 125137737Smckusick /* 125237737Smckusick * Return target name of a symbolic link 125337737Smckusick */ 125437737Smckusick ufs_readlink(vp, uiop, cred) 125537737Smckusick struct vnode *vp; 125637737Smckusick struct uio *uiop; 125737737Smckusick struct ucred *cred; 125837737Smckusick { 125937737Smckusick 126039597Smckusick return (ufs_read(vp, uiop, 0, cred)); 126137737Smckusick } 126237737Smckusick 126337737Smckusick /* 126437737Smckusick * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 126542466Smckusick * done. Nothing to do at the moment. 126637737Smckusick */ 126742466Smckusick /* ARGSUSED */ 126837737Smckusick ufs_abortop(ndp) 126942466Smckusick struct nameidata *ndp; 127037737Smckusick { 127137737Smckusick 127242466Smckusick return (0); 127312756Ssam } 127412756Ssam 127539909Smckusick /* 127639909Smckusick * Lock an inode. 127739909Smckusick */ 127837737Smckusick ufs_lock(vp) 127937737Smckusick struct vnode *vp; 128037737Smckusick { 128137737Smckusick register struct inode *ip = VTOI(vp); 128237737Smckusick 128337737Smckusick ILOCK(ip); 128437737Smckusick return (0); 128537737Smckusick } 128637737Smckusick 128739909Smckusick /* 128839909Smckusick * Unlock an inode. 128939909Smckusick */ 129037737Smckusick ufs_unlock(vp) 129137737Smckusick struct vnode *vp; 129237737Smckusick { 129337737Smckusick register struct inode *ip = VTOI(vp); 129437737Smckusick 129537737Smckusick if (!(ip->i_flag & ILOCKED)) 129637737Smckusick panic("ufs_unlock NOT LOCKED"); 129737737Smckusick IUNLOCK(ip); 129837737Smckusick return (0); 129937737Smckusick } 130037737Smckusick 130112756Ssam /* 130239909Smckusick * Check for a locked inode. 130339909Smckusick */ 130439909Smckusick ufs_islocked(vp) 130539909Smckusick struct vnode *vp; 130639909Smckusick { 130739909Smckusick 130839909Smckusick if (VTOI(vp)->i_flag & ILOCKED) 130939909Smckusick return (1); 131039909Smckusick return (0); 131139909Smckusick } 131239909Smckusick 131339909Smckusick /* 131437737Smckusick * Get access to bmap 131512756Ssam */ 131637737Smckusick ufs_bmap(vp, bn, vpp, bnp) 131737737Smckusick struct vnode *vp; 131837737Smckusick daddr_t bn; 131937737Smckusick struct vnode **vpp; 132037737Smckusick daddr_t *bnp; 132112756Ssam { 132237737Smckusick struct inode *ip = VTOI(vp); 132312756Ssam 132437737Smckusick if (vpp != NULL) 132537737Smckusick *vpp = ip->i_devvp; 132637737Smckusick if (bnp == NULL) 132737737Smckusick return (0); 132841538Smckusick return (bmap(ip, bn, bnp)); 132912756Ssam } 133037737Smckusick 133137737Smckusick /* 133241538Smckusick * Calculate the logical to physical mapping if not done already, 133341538Smckusick * then call the device strategy routine. 133437737Smckusick */ 133541538Smckusick int checkoverlap = 0; 133639674Smckusick 133737737Smckusick ufs_strategy(bp) 133837737Smckusick register struct buf *bp; 133937737Smckusick { 134039674Smckusick register struct inode *ip = VTOI(bp->b_vp); 134139674Smckusick struct vnode *vp; 134239674Smckusick int error; 134339674Smckusick 134439674Smckusick if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 134539674Smckusick panic("ufs_strategy: spec"); 134639674Smckusick if (bp->b_blkno == bp->b_lblkno) { 134739674Smckusick if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno)) 134839674Smckusick return (error); 134939896Smckusick if ((long)bp->b_blkno == -1) 135039674Smckusick clrbuf(bp); 135139674Smckusick } 135239896Smckusick if ((long)bp->b_blkno == -1) { 135339896Smckusick biodone(bp); 135439674Smckusick return (0); 135539896Smckusick } 135641538Smckusick #ifdef DIAGNOSTIC 135739674Smckusick if (checkoverlap) { 135841538Smckusick register struct buf *ep; 135941538Smckusick struct buf *ebp; 136041538Smckusick daddr_t start, last; 136141538Smckusick 136239674Smckusick ebp = &buf[nbuf]; 136339674Smckusick start = bp->b_blkno; 136439674Smckusick last = start + btodb(bp->b_bcount) - 1; 136539674Smckusick for (ep = buf; ep < ebp; ep++) { 136639674Smckusick if (ep == bp || (ep->b_flags & B_INVAL) || 136741396Smckusick ep->b_vp == NULLVP) 136839674Smckusick continue; 136939674Smckusick if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0)) 137039674Smckusick continue; 137139674Smckusick if (vp != ip->i_devvp) 137239674Smckusick continue; 137339674Smckusick /* look for overlap */ 137439674Smckusick if (ep->b_bcount == 0 || ep->b_blkno > last || 137539674Smckusick ep->b_blkno + btodb(ep->b_bcount) <= start) 137639674Smckusick continue; 137739896Smckusick vprint("Disk overlap", vp); 137839896Smckusick printf("\tstart %d, end %d overlap start %d, end %d\n", 137939896Smckusick start, last, ep->b_blkno, 138039896Smckusick ep->b_blkno + btodb(ep->b_bcount) - 1); 138141538Smckusick panic("Disk buffer overlap"); 138239674Smckusick } 138339674Smckusick } 138441538Smckusick #endif /* DIAGNOSTIC */ 138539674Smckusick vp = ip->i_devvp; 138639674Smckusick bp->b_dev = vp->v_rdev; 138739674Smckusick (*(vp->v_op->vn_strategy))(bp); 138837737Smckusick return (0); 138937737Smckusick } 139037737Smckusick 139137737Smckusick /* 139239674Smckusick * Print out the contents of an inode. 139339674Smckusick */ 139439674Smckusick ufs_print(vp) 139539674Smckusick struct vnode *vp; 139639674Smckusick { 139739674Smckusick register struct inode *ip = VTOI(vp); 139839674Smckusick 139940293Smckusick printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number, 140040293Smckusick major(ip->i_dev), minor(ip->i_dev)); 140140293Smckusick #ifdef FIFO 140240293Smckusick if (vp->v_type == VFIFO) 140340293Smckusick fifo_printinfo(vp); 140440293Smckusick #endif /* FIFO */ 140540293Smckusick printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : ""); 140639900Smckusick if (ip->i_spare0 == 0) 140739900Smckusick return; 140839900Smckusick printf("\towner pid %d", ip->i_spare0); 140939900Smckusick if (ip->i_spare1) 141039900Smckusick printf(" waiting pid %d", ip->i_spare1); 141139900Smckusick printf("\n"); 141239674Smckusick } 141339674Smckusick 141439674Smckusick /* 141539628Smckusick * Read wrapper for special devices. 141639628Smckusick */ 141739628Smckusick ufsspec_read(vp, uio, ioflag, cred) 141839628Smckusick struct vnode *vp; 141939628Smckusick struct uio *uio; 142039628Smckusick int ioflag; 142139628Smckusick struct ucred *cred; 142239628Smckusick { 142339628Smckusick 142439628Smckusick /* 142539628Smckusick * Set access flag. 142639628Smckusick */ 142739628Smckusick VTOI(vp)->i_flag |= IACC; 142839628Smckusick return (spec_read(vp, uio, ioflag, cred)); 142939628Smckusick } 143039628Smckusick 143139628Smckusick /* 143239628Smckusick * Write wrapper for special devices. 143339628Smckusick */ 143439628Smckusick ufsspec_write(vp, uio, ioflag, cred) 143539628Smckusick struct vnode *vp; 143639628Smckusick struct uio *uio; 143739628Smckusick int ioflag; 143839628Smckusick struct ucred *cred; 143939628Smckusick { 144039628Smckusick 144139628Smckusick /* 144239628Smckusick * Set update and change flags. 144339628Smckusick */ 144439628Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 144539628Smckusick return (spec_write(vp, uio, ioflag, cred)); 144639628Smckusick } 144739628Smckusick 144839628Smckusick /* 144939628Smckusick * Close wrapper for special devices. 145039628Smckusick * 145139628Smckusick * Update the times on the inode then do device close. 145239628Smckusick */ 1453*48039Smckusick ufsspec_close(vp, fflag, cred, p) 145439628Smckusick struct vnode *vp; 145539628Smckusick int fflag; 145639628Smckusick struct ucred *cred; 1457*48039Smckusick struct proc *p; 145839628Smckusick { 145939628Smckusick register struct inode *ip = VTOI(vp); 146039628Smckusick 146139815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 146239628Smckusick ITIMES(ip, &time, &time); 1463*48039Smckusick return (spec_close(vp, fflag, cred, p)); 146439628Smckusick } 146539628Smckusick 146640290Smckusick #ifdef FIFO 146739628Smckusick /* 146840290Smckusick * Read wrapper for fifo's 146940290Smckusick */ 147040290Smckusick ufsfifo_read(vp, uio, ioflag, cred) 147140290Smckusick struct vnode *vp; 147240290Smckusick struct uio *uio; 147340290Smckusick int ioflag; 147440290Smckusick struct ucred *cred; 147540290Smckusick { 147640290Smckusick 147740290Smckusick /* 147840290Smckusick * Set access flag. 147940290Smckusick */ 148040290Smckusick VTOI(vp)->i_flag |= IACC; 148140290Smckusick return (fifo_read(vp, uio, ioflag, cred)); 148240290Smckusick } 148340290Smckusick 148440290Smckusick /* 148540290Smckusick * Write wrapper for fifo's. 148640290Smckusick */ 148740290Smckusick ufsfifo_write(vp, uio, ioflag, cred) 148840290Smckusick struct vnode *vp; 148940290Smckusick struct uio *uio; 149040290Smckusick int ioflag; 149140290Smckusick struct ucred *cred; 149240290Smckusick { 149340290Smckusick 149440290Smckusick /* 149540290Smckusick * Set update and change flags. 149640290Smckusick */ 149740290Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 149840290Smckusick return (fifo_write(vp, uio, ioflag, cred)); 149940290Smckusick } 150040290Smckusick 150140290Smckusick /* 150240290Smckusick * Close wrapper for fifo's. 150340290Smckusick * 150440290Smckusick * Update the times on the inode then do device close. 150540290Smckusick */ 1506*48039Smckusick ufsfifo_close(vp, fflag, cred, p) 150740290Smckusick struct vnode *vp; 150840290Smckusick int fflag; 150940290Smckusick struct ucred *cred; 1510*48039Smckusick struct proc *p; 151140290Smckusick { 151240290Smckusick register struct inode *ip = VTOI(vp); 151340290Smckusick 151440290Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 151540290Smckusick ITIMES(ip, &time, &time); 1516*48039Smckusick return (fifo_close(vp, fflag, cred, p)); 151740290Smckusick } 151840290Smckusick #endif /* FIFO */ 151940290Smckusick 152040290Smckusick /* 152137737Smckusick * Make a new file. 152237737Smckusick */ 152337737Smckusick maknode(mode, ndp, ipp) 152437737Smckusick int mode; 152537737Smckusick register struct nameidata *ndp; 152637737Smckusick struct inode **ipp; 152737737Smckusick { 152837737Smckusick register struct inode *ip; 152937737Smckusick struct inode *tip; 153037737Smckusick register struct inode *pdir = VTOI(ndp->ni_dvp); 153137737Smckusick ino_t ipref; 153237737Smckusick int error; 153337737Smckusick 153437737Smckusick *ipp = 0; 153541312Smckusick if ((mode & IFMT) == 0) 153641312Smckusick mode |= IFREG; 153737737Smckusick if ((mode & IFMT) == IFDIR) 153837737Smckusick ipref = dirpref(pdir->i_fs); 153937737Smckusick else 154037737Smckusick ipref = pdir->i_number; 154141312Smckusick if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { 154237737Smckusick iput(pdir); 154337737Smckusick return (error); 154437737Smckusick } 154537737Smckusick ip = tip; 154641312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 154741312Smckusick ip->i_gid = pdir->i_gid; 154837737Smckusick #ifdef QUOTA 154941312Smckusick if ((error = getinoquota(ip)) || 155041312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 155141312Smckusick ifree(ip, ip->i_number, mode); 155241312Smckusick iput(ip); 155341312Smckusick iput(pdir); 155441312Smckusick return (error); 155541312Smckusick } 155637737Smckusick #endif 155737737Smckusick ip->i_flag |= IACC|IUPD|ICHG; 155837737Smckusick ip->i_mode = mode; 155937737Smckusick ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ 156037737Smckusick ip->i_nlink = 1; 156137737Smckusick if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && 156237737Smckusick suser(ndp->ni_cred, NULL)) 156337737Smckusick ip->i_mode &= ~ISGID; 156437737Smckusick 156537737Smckusick /* 156637737Smckusick * Make sure inode goes to disk before directory entry. 156737737Smckusick */ 156841312Smckusick if (error = iupdat(ip, &time, &time, 1)) 156941312Smckusick goto bad; 157047219Smckusick if (error = direnter(ip, ndp)) 157141312Smckusick goto bad; 157247219Smckusick iput(pdir); 157337737Smckusick *ipp = ip; 157437737Smckusick return (0); 157541312Smckusick 157641312Smckusick bad: 157741312Smckusick /* 157841312Smckusick * Write error occurred trying to update the inode 157941312Smckusick * or the directory so must deallocate the inode. 158041312Smckusick */ 158147219Smckusick iput(pdir); 158241312Smckusick ip->i_nlink = 0; 158341312Smckusick ip->i_flag |= ICHG; 158441312Smckusick iput(ip); 158541312Smckusick return (error); 158637737Smckusick } 158746207Smckusick 158846207Smckusick /* 158946207Smckusick * Advisory record locking support 159046207Smckusick */ 159146207Smckusick ufs_advlock(vp, id, op, fl, flags) 159246207Smckusick struct vnode *vp; 159346207Smckusick caddr_t id; 159446207Smckusick int op; 159546207Smckusick register struct flock *fl; 159646207Smckusick int flags; 159746207Smckusick { 159846207Smckusick register struct inode *ip = VTOI(vp); 159946207Smckusick register struct lockf *lock; 160046207Smckusick off_t start, end; 160146207Smckusick int error; 160246207Smckusick 160346207Smckusick /* 160446207Smckusick * Avoid the common case of unlocking when inode has no locks. 160546207Smckusick */ 160646207Smckusick if (ip->i_lockf == (struct lockf *)0) { 160746207Smckusick if (op != F_SETLK) { 160846207Smckusick fl->l_type = F_UNLCK; 160946207Smckusick return (0); 161046207Smckusick } 161146207Smckusick } 161246207Smckusick /* 161346207Smckusick * Convert the flock structure into a start and end. 161446207Smckusick */ 161546207Smckusick switch (fl->l_whence) { 161646207Smckusick 161746207Smckusick case SEEK_SET: 161846207Smckusick case SEEK_CUR: 161946207Smckusick /* 162046207Smckusick * Caller is responsible for adding any necessary offset 162146207Smckusick * when SEEK_CUR is used. 162246207Smckusick */ 162346207Smckusick start = fl->l_start; 162446207Smckusick break; 162546207Smckusick 162646207Smckusick case SEEK_END: 162746207Smckusick start = ip->i_size + fl->l_start; 162846207Smckusick break; 162946207Smckusick 163046207Smckusick default: 163146207Smckusick return (EINVAL); 163246207Smckusick } 163346207Smckusick if (start < 0) 163446207Smckusick return (EINVAL); 163546207Smckusick if (fl->l_len == 0) 163646207Smckusick end = -1; 163746207Smckusick else 163846507Smckusick end = start + fl->l_len - 1; 163946207Smckusick /* 164046207Smckusick * Create the lockf structure 164146207Smckusick */ 164246207Smckusick MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); 164346207Smckusick lock->lf_start = start; 164446207Smckusick lock->lf_end = end; 164546207Smckusick lock->lf_id = id; 164646207Smckusick lock->lf_inode = ip; 164746207Smckusick lock->lf_type = fl->l_type; 164846207Smckusick lock->lf_next = (struct lockf *)0; 164946207Smckusick lock->lf_block = (struct lockf *)0; 165046207Smckusick lock->lf_flags = flags; 165146207Smckusick /* 165246207Smckusick * Do the requested operation. 165346207Smckusick */ 165446207Smckusick switch(op) { 165546207Smckusick case F_SETLK: 165646679Smckusick return (lf_setlock(lock)); 165746207Smckusick 165846207Smckusick case F_UNLCK: 165946679Smckusick error = lf_clearlock(lock); 166046679Smckusick FREE(lock, M_LOCKF); 166146679Smckusick return (error); 166246207Smckusick 166346207Smckusick case F_GETLK: 166446679Smckusick error = lf_getlock(lock, fl); 166546679Smckusick FREE(lock, M_LOCKF); 166646679Smckusick return (error); 166746207Smckusick 166846207Smckusick default: 166946207Smckusick free(lock, M_LOCKF); 167046207Smckusick return (EINVAL); 167146207Smckusick } 167246207Smckusick /* NOTREACHED */ 167346207Smckusick } 1674*48039Smckusick 1675*48039Smckusick /* 1676*48039Smckusick * Global vfs data structures for ufs 1677*48039Smckusick */ 1678*48039Smckusick struct vnodeops ufs_vnodeops = { 1679*48039Smckusick ufs_lookup, /* lookup */ 1680*48039Smckusick ufs_create, /* create */ 1681*48039Smckusick ufs_mknod, /* mknod */ 1682*48039Smckusick ufs_open, /* open */ 1683*48039Smckusick ufs_close, /* close */ 1684*48039Smckusick ufs_access, /* access */ 1685*48039Smckusick ufs_getattr, /* getattr */ 1686*48039Smckusick ufs_setattr, /* setattr */ 1687*48039Smckusick ufs_read, /* read */ 1688*48039Smckusick ufs_write, /* write */ 1689*48039Smckusick ufs_ioctl, /* ioctl */ 1690*48039Smckusick ufs_select, /* select */ 1691*48039Smckusick ufs_mmap, /* mmap */ 1692*48039Smckusick ufs_fsync, /* fsync */ 1693*48039Smckusick ufs_seek, /* seek */ 1694*48039Smckusick ufs_remove, /* remove */ 1695*48039Smckusick ufs_link, /* link */ 1696*48039Smckusick ufs_rename, /* rename */ 1697*48039Smckusick ufs_mkdir, /* mkdir */ 1698*48039Smckusick ufs_rmdir, /* rmdir */ 1699*48039Smckusick ufs_symlink, /* symlink */ 1700*48039Smckusick ufs_readdir, /* readdir */ 1701*48039Smckusick ufs_readlink, /* readlink */ 1702*48039Smckusick ufs_abortop, /* abortop */ 1703*48039Smckusick ufs_inactive, /* inactive */ 1704*48039Smckusick ufs_reclaim, /* reclaim */ 1705*48039Smckusick ufs_lock, /* lock */ 1706*48039Smckusick ufs_unlock, /* unlock */ 1707*48039Smckusick ufs_bmap, /* bmap */ 1708*48039Smckusick ufs_strategy, /* strategy */ 1709*48039Smckusick ufs_print, /* print */ 1710*48039Smckusick ufs_islocked, /* islocked */ 1711*48039Smckusick ufs_advlock, /* advlock */ 1712*48039Smckusick }; 1713*48039Smckusick 1714*48039Smckusick struct vnodeops spec_inodeops = { 1715*48039Smckusick spec_lookup, /* lookup */ 1716*48039Smckusick spec_create, /* create */ 1717*48039Smckusick spec_mknod, /* mknod */ 1718*48039Smckusick spec_open, /* open */ 1719*48039Smckusick ufsspec_close, /* close */ 1720*48039Smckusick ufs_access, /* access */ 1721*48039Smckusick ufs_getattr, /* getattr */ 1722*48039Smckusick ufs_setattr, /* setattr */ 1723*48039Smckusick ufsspec_read, /* read */ 1724*48039Smckusick ufsspec_write, /* write */ 1725*48039Smckusick spec_ioctl, /* ioctl */ 1726*48039Smckusick spec_select, /* select */ 1727*48039Smckusick spec_mmap, /* mmap */ 1728*48039Smckusick spec_fsync, /* fsync */ 1729*48039Smckusick spec_seek, /* seek */ 1730*48039Smckusick spec_remove, /* remove */ 1731*48039Smckusick spec_link, /* link */ 1732*48039Smckusick spec_rename, /* rename */ 1733*48039Smckusick spec_mkdir, /* mkdir */ 1734*48039Smckusick spec_rmdir, /* rmdir */ 1735*48039Smckusick spec_symlink, /* symlink */ 1736*48039Smckusick spec_readdir, /* readdir */ 1737*48039Smckusick spec_readlink, /* readlink */ 1738*48039Smckusick spec_abortop, /* abortop */ 1739*48039Smckusick ufs_inactive, /* inactive */ 1740*48039Smckusick ufs_reclaim, /* reclaim */ 1741*48039Smckusick ufs_lock, /* lock */ 1742*48039Smckusick ufs_unlock, /* unlock */ 1743*48039Smckusick spec_bmap, /* bmap */ 1744*48039Smckusick spec_strategy, /* strategy */ 1745*48039Smckusick ufs_print, /* print */ 1746*48039Smckusick ufs_islocked, /* islocked */ 1747*48039Smckusick spec_advlock, /* advlock */ 1748*48039Smckusick }; 1749*48039Smckusick 1750*48039Smckusick #ifdef FIFO 1751*48039Smckusick struct vnodeops fifo_inodeops = { 1752*48039Smckusick fifo_lookup, /* lookup */ 1753*48039Smckusick fifo_create, /* create */ 1754*48039Smckusick fifo_mknod, /* mknod */ 1755*48039Smckusick fifo_open, /* open */ 1756*48039Smckusick ufsfifo_close, /* close */ 1757*48039Smckusick ufs_access, /* access */ 1758*48039Smckusick ufs_getattr, /* getattr */ 1759*48039Smckusick ufs_setattr, /* setattr */ 1760*48039Smckusick ufsfifo_read, /* read */ 1761*48039Smckusick ufsfifo_write, /* write */ 1762*48039Smckusick fifo_ioctl, /* ioctl */ 1763*48039Smckusick fifo_select, /* select */ 1764*48039Smckusick fifo_mmap, /* mmap */ 1765*48039Smckusick fifo_fsync, /* fsync */ 1766*48039Smckusick fifo_seek, /* seek */ 1767*48039Smckusick fifo_remove, /* remove */ 1768*48039Smckusick fifo_link, /* link */ 1769*48039Smckusick fifo_rename, /* rename */ 1770*48039Smckusick fifo_mkdir, /* mkdir */ 1771*48039Smckusick fifo_rmdir, /* rmdir */ 1772*48039Smckusick fifo_symlink, /* symlink */ 1773*48039Smckusick fifo_readdir, /* readdir */ 1774*48039Smckusick fifo_readlink, /* readlink */ 1775*48039Smckusick fifo_abortop, /* abortop */ 1776*48039Smckusick ufs_inactive, /* inactive */ 1777*48039Smckusick ufs_reclaim, /* reclaim */ 1778*48039Smckusick ufs_lock, /* lock */ 1779*48039Smckusick ufs_unlock, /* unlock */ 1780*48039Smckusick fifo_bmap, /* bmap */ 1781*48039Smckusick fifo_strategy, /* strategy */ 1782*48039Smckusick ufs_print, /* print */ 1783*48039Smckusick ufs_islocked, /* islocked */ 1784*48039Smckusick fifo_advlock, /* advlock */ 1785*48039Smckusick }; 1786*48039Smckusick #endif /* FIFO */ 1787*48039Smckusick 1788*48039Smckusick enum vtype iftovt_tab[16] = { 1789*48039Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 1790*48039Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 1791*48039Smckusick }; 1792*48039Smckusick int vttoif_tab[9] = { 1793*48039Smckusick 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT, 1794*48039Smckusick }; 1795