xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 7701)
1*7701Ssam /*	vfs_syscalls.c	4.32	82/08/10	*/
237Sbill 
337Sbill #include "../h/param.h"
437Sbill #include "../h/systm.h"
537Sbill #include "../h/dir.h"
637Sbill #include "../h/user.h"
76254Sroot #include "../h/file.h"
86574Smckusic #include "../h/stat.h"
937Sbill #include "../h/inode.h"
106574Smckusic #include "../h/fs.h"
116254Sroot #include "../h/buf.h"
126254Sroot #include "../h/proc.h"
136254Sroot #include "../h/inline.h"
14*7701Ssam /* no reason to inline expand these guys here */
15*7701Ssam #undef ilock
16*7701Ssam #undef iunlock
177482Skre #include "../h/quota.h"
187505Sroot #include "../h/descrip.h"
1937Sbill 
206254Sroot chdir()
216254Sroot {
226254Sroot 
236254Sroot 	chdirec(&u.u_cdir);
246254Sroot }
256254Sroot 
266254Sroot chroot()
276254Sroot {
286254Sroot 
296254Sroot 	if (suser())
306254Sroot 		chdirec(&u.u_rdir);
316254Sroot }
326254Sroot 
336254Sroot chdirec(ipp)
34*7701Ssam 	register struct inode **ipp;
356254Sroot {
366254Sroot 	register struct inode *ip;
376254Sroot 	struct a {
386254Sroot 		char	*fname;
396254Sroot 	};
406254Sroot 
416254Sroot 	ip = namei(uchar, 0, 1);
426254Sroot 	if(ip == NULL)
436254Sroot 		return;
446254Sroot 	if((ip->i_mode&IFMT) != IFDIR) {
456254Sroot 		u.u_error = ENOTDIR;
466254Sroot 		goto bad;
476254Sroot 	}
486254Sroot 	if(access(ip, IEXEC))
496254Sroot 		goto bad;
507122Smckusick 	iunlock(ip);
517142Smckusick 	if (*ipp)
527142Smckusick 		irele(*ipp);
536254Sroot 	*ipp = ip;
546254Sroot 	return;
556254Sroot 
566254Sroot bad:
576254Sroot 	iput(ip);
586254Sroot }
596254Sroot 
6037Sbill /*
616254Sroot  * Open system call.
626254Sroot  */
636254Sroot open()
646254Sroot {
656254Sroot 	register struct inode *ip;
666254Sroot 	register struct a {
676254Sroot 		char	*fname;
68*7701Ssam 		int	flags;
69*7701Ssam 		int	mode;
706254Sroot 	} *uap;
71*7701Ssam 	int checkpermissions = 1;
726254Sroot 
736254Sroot 	uap = (struct a *)u.u_ap;
74*7701Ssam 	if (uap->flags&FCREATE) {
75*7701Ssam 		ip = namei(uchar, 1, 1);
76*7701Ssam 		if (ip == NULL) {
77*7701Ssam 			if (u.u_error)
78*7701Ssam 				return;
79*7701Ssam 			ip = maknode(uap->mode&07777&(~ISVTX));
80*7701Ssam 			checkpermissions = 0;
81*7701Ssam 			uap->flags &= ~FTRUNCATE;
82*7701Ssam 		}
83*7701Ssam 	} else
84*7701Ssam 		ip = namei(uchar, 0, 1);
856254Sroot 	if (ip == NULL)
866254Sroot 		return;
87*7701Ssam 	open1(ip, ++uap->flags, checkpermissions);
886254Sroot }
896254Sroot 
90*7701Ssam #ifndef NOCOMPAT
916254Sroot /*
926254Sroot  * Creat system call.
936254Sroot  */
947505Sroot ocreat()
956254Sroot {
966254Sroot 	register struct inode *ip;
976254Sroot 	register struct a {
986254Sroot 		char	*fname;
996254Sroot 		int	fmode;
1006254Sroot 	} *uap;
1016254Sroot 
1026254Sroot 	uap = (struct a *)u.u_ap;
1036254Sroot 	ip = namei(uchar, 1, 1);
1046254Sroot 	if (ip == NULL) {
1056254Sroot 		if (u.u_error)
1066254Sroot 			return;
1076254Sroot 		ip = maknode(uap->fmode&07777&(~ISVTX));
108*7701Ssam 		if (ip == NULL)
1096254Sroot 			return;
110*7701Ssam 		open1(ip, FWRITE, 0);
1116254Sroot 	} else
112*7701Ssam 		open1(ip, FWRITE|FTRUNCATE, 0);
1136254Sroot }
114*7701Ssam #endif
1156254Sroot 
1166254Sroot /*
1176254Sroot  * Common code for open and creat.
118*7701Ssam  * Check permissions (if we haven't done so already),
119*7701Ssam  * allocate an open file structure, and call
120*7701Ssam  * the device open routine, if any.
1216254Sroot  */
122*7701Ssam open1(ip, mode, checkpermissions)
1236254Sroot 	register struct inode *ip;
1246254Sroot 	register mode;
1256254Sroot {
1266254Sroot 	register struct file *fp;
127*7701Ssam 	int i, flags;
1286254Sroot 
129*7701Ssam 	if (checkpermissions) {
1306254Sroot 		if (mode&FREAD)
131*7701Ssam 			if (access(ip, IREAD))
132*7701Ssam 				goto bad;
1336254Sroot 		if (mode&FWRITE) {
134*7701Ssam 			if (access(ip, IWRITE))
135*7701Ssam 				goto bad;
136*7701Ssam 			if ((ip->i_mode&IFMT) == IFDIR) {
1376254Sroot 				u.u_error = EISDIR;
138*7701Ssam 				goto bad;
139*7701Ssam 			}
1406254Sroot 		}
1416254Sroot 	}
142*7701Ssam 
143*7701Ssam 	/*
144*7701Ssam 	 * Check locking on inode.  Release "inode lock"
145*7701Ssam 	 * while doing so in case we block inside flocki.
146*7701Ssam 	 */
147*7701Ssam 	flags = 0;
148*7701Ssam 	if (mode&(FRDLOCK|FWRLOCK)) {
149*7701Ssam 		iunlock(ip);
150*7701Ssam 		flags = flocki(ip, 0, mode);
151*7701Ssam 		ilock(ip);
152*7701Ssam 		if (u.u_error)
153*7701Ssam 			goto bad;
1547142Smckusick 	}
155*7701Ssam 	if (mode&FTRUNCATE)
156*7701Ssam 		itrunc(ip, 0);
1577122Smckusick 	iunlock(ip);
1586254Sroot 	if ((fp = falloc()) == NULL)
1596254Sroot 		goto out;
160*7701Ssam 	fp->f_flag = mode & FMODES;
1617505Sroot 	fp->f_type = DTYPE_FILE;
1626254Sroot 	i = u.u_r.r_val1;
1636254Sroot 	fp->f_inode = ip;
164*7701Ssam 	openi(ip, mode);
165*7701Ssam 	if (u.u_error == 0) {
166*7701Ssam 		u.u_pofile[i] = flags;
1676254Sroot 		return;
168*7701Ssam 	}
1696254Sroot 	u.u_ofile[i] = NULL;
1706254Sroot 	fp->f_count--;
1716254Sroot out:
1727142Smckusick 	irele(ip);
173*7701Ssam 	return;
174*7701Ssam bad:
175*7701Ssam 	iput(ip);
1766254Sroot }
1776254Sroot 
1786254Sroot /*
1796254Sroot  * Mknod system call
1806254Sroot  */
1816254Sroot mknod()
1826254Sroot {
1836254Sroot 	register struct inode *ip;
1846254Sroot 	register struct a {
1856254Sroot 		char	*fname;
1866254Sroot 		int	fmode;
1876254Sroot 		int	dev;
1886254Sroot 	} *uap;
1896254Sroot 
1906254Sroot 	uap = (struct a *)u.u_ap;
1916254Sroot 	if (suser()) {
1926254Sroot 		ip = namei(uchar, 1, 0);
1936254Sroot 		if (ip != NULL) {
1946254Sroot 			u.u_error = EEXIST;
1956254Sroot 			goto out;
1966254Sroot 		}
1976254Sroot 	}
1986254Sroot 	if (u.u_error)
1996254Sroot 		return;
2006254Sroot 	ip = maknode(uap->fmode);
2016254Sroot 	if (ip == NULL)
2026254Sroot 		return;
2036254Sroot 	if (uap->dev) {
2046254Sroot 		/*
2056254Sroot 		 * Want to be able to use this to make badblock
2066254Sroot 		 * inodes, so don't truncate the dev number.
2076254Sroot 		 */
2086574Smckusic 		ip->i_rdev = uap->dev;
2096254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
2106254Sroot 	}
2116254Sroot 
2126254Sroot out:
2136254Sroot 	iput(ip);
2146254Sroot }
2156254Sroot 
2166254Sroot /*
2176254Sroot  * link system call
2186254Sroot  */
2196254Sroot link()
2206254Sroot {
2216254Sroot 	register struct inode *ip, *xp;
2226254Sroot 	register struct a {
2236254Sroot 		char	*target;
2246254Sroot 		char	*linkname;
2256254Sroot 	} *uap;
2266254Sroot 
2276254Sroot 	uap = (struct a *)u.u_ap;
2286254Sroot 	ip = namei(uchar, 0, 1);    /* well, this routine is doomed anyhow */
2296254Sroot 	if (ip == NULL)
2306254Sroot 		return;
2317439Sroot 	if ((ip->i_mode&IFMT)==IFDIR && !suser()) {
2327439Sroot 		iput(ip);
2337439Sroot 		return;
2347439Sroot 	}
2356254Sroot 	ip->i_nlink++;
2366254Sroot 	ip->i_flag |= ICHG;
2376254Sroot 	iupdat(ip, &time, &time, 1);
2387122Smckusick 	iunlock(ip);
2396254Sroot 	u.u_dirp = (caddr_t)uap->linkname;
2406254Sroot 	xp = namei(uchar, 1, 0);
2416254Sroot 	if (xp != NULL) {
2426254Sroot 		u.u_error = EEXIST;
2436254Sroot 		iput(xp);
2446254Sroot 		goto out;
2456254Sroot 	}
2466254Sroot 	if (u.u_error)
2476254Sroot 		goto out;
2486254Sroot 	if (u.u_pdir->i_dev != ip->i_dev) {
2496254Sroot 		iput(u.u_pdir);
2506254Sroot 		u.u_error = EXDEV;
2516254Sroot 		goto out;
2526254Sroot 	}
2537535Sroot 	direnter(ip);
2546254Sroot out:
2556254Sroot 	if (u.u_error) {
2566254Sroot 		ip->i_nlink--;
2576254Sroot 		ip->i_flag |= ICHG;
2586254Sroot 	}
2596254Sroot out1:
2607142Smckusick 	irele(ip);
2616254Sroot }
2626254Sroot 
2636254Sroot /*
2646254Sroot  * symlink -- make a symbolic link
2656254Sroot  */
2666254Sroot symlink()
2676254Sroot {
2686254Sroot 	register struct a {
2696254Sroot 		char	*target;
2706254Sroot 		char	*linkname;
2716254Sroot 	} *uap;
2726254Sroot 	register struct inode *ip;
2736254Sroot 	register char *tp;
2746254Sroot 	register c, nc;
2756254Sroot 
2766254Sroot 	uap = (struct a *)u.u_ap;
2776254Sroot 	tp = uap->target;
2786254Sroot 	nc = 0;
2796254Sroot 	while (c = fubyte(tp)) {
2806254Sroot 		if (c < 0) {
2816254Sroot 			u.u_error = EFAULT;
2826254Sroot 			return;
2836254Sroot 		}
2846254Sroot 		tp++;
2856254Sroot 		nc++;
2866254Sroot 	}
2876254Sroot 	u.u_dirp = uap->linkname;
2886254Sroot 	ip = namei(uchar, 1, 0);
2896254Sroot 	if (ip) {
2906254Sroot 		iput(ip);
2916254Sroot 		u.u_error = EEXIST;
2926254Sroot 		return;
2936254Sroot 	}
2946254Sroot 	if (u.u_error)
2956254Sroot 		return;
2966254Sroot 	ip = maknode(IFLNK | 0777);
2976254Sroot 	if (ip == NULL)
2986254Sroot 		return;
2996254Sroot 	u.u_base = uap->target;
3006254Sroot 	u.u_count = nc;
3016254Sroot 	u.u_offset = 0;
3026254Sroot 	u.u_segflg = 0;
3036254Sroot 	writei(ip);
3046254Sroot 	iput(ip);
3056254Sroot }
3066254Sroot 
3076254Sroot /*
3086254Sroot  * Unlink system call.
3096254Sroot  * Hard to avoid races here, especially
3106254Sroot  * in unlinking directories.
3116254Sroot  */
3126254Sroot unlink()
3136254Sroot {
3146254Sroot 	register struct inode *ip, *pp;
3156254Sroot 	struct a {
3166254Sroot 		char	*fname;
3176254Sroot 	};
3186574Smckusic 	struct fs *fs;
3196574Smckusic 	struct buf *bp;
3206574Smckusic 	int lbn, bn, base;
3217142Smckusick 	int unlinkingdot = 0;
3226254Sroot 
3236254Sroot 	pp = namei(uchar, 2, 0);
3247535Sroot 	if (pp == NULL)
3256254Sroot 		return;
3267439Sroot 
3276254Sroot 	/*
3286254Sroot 	 * Check for unlink(".")
3296254Sroot 	 * to avoid hanging on the iget
3306254Sroot 	 */
3316254Sroot 	if (pp->i_number == u.u_dent.d_ino) {
3326254Sroot 		ip = pp;
3336254Sroot 		ip->i_count++;
3347142Smckusick 		unlinkingdot++;
3356254Sroot 	} else
3366574Smckusic 		ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
3376254Sroot 	if(ip == NULL)
3386254Sroot 		goto out1;
3396254Sroot 	if((ip->i_mode&IFMT)==IFDIR && !suser())
3406254Sroot 		goto out;
3416254Sroot 	/*
3426254Sroot 	 * Don't unlink a mounted file.
3436254Sroot 	 */
3446254Sroot 	if (ip->i_dev != pp->i_dev) {
3456254Sroot 		u.u_error = EBUSY;
3466254Sroot 		goto out;
3476254Sroot 	}
3486254Sroot 	if (ip->i_flag&ITEXT)
3496254Sroot 		xrele(ip);	/* try once to free text */
3507535Sroot 	if (dirremove()) {
3517535Sroot 		ip->i_nlink--;
3527535Sroot 		ip->i_flag |= ICHG;
3536254Sroot 	}
3546254Sroot out:
3557142Smckusick 	if (unlinkingdot)
3567142Smckusick 		irele(ip);
3577142Smckusick 	else
3587142Smckusick 		iput(ip);
3596254Sroot out1:
3606254Sroot 	iput(pp);
3616254Sroot }
3626254Sroot 
3636254Sroot /*
3646254Sroot  * Seek system call
3656254Sroot  */
3666254Sroot seek()
3676254Sroot {
3686254Sroot 	register struct file *fp;
3696254Sroot 	register struct a {
370*7701Ssam 		int	fd;
3716254Sroot 		off_t	off;
3726254Sroot 		int	sbase;
3736254Sroot 	} *uap;
3746254Sroot 
3756254Sroot 	uap = (struct a *)u.u_ap;
376*7701Ssam 	fp = getf(uap->fd);
3776254Sroot 	if (fp == NULL)
3786254Sroot 		return;
3797505Sroot 	if (fp->f_type == DTYPE_SOCKET) {
3806254Sroot 		u.u_error = ESPIPE;
3816254Sroot 		return;
3826254Sroot 	}
383*7701Ssam 	if (uap->sbase == FSEEK_RELATIVE)
3846254Sroot 		uap->off += fp->f_offset;
385*7701Ssam 	else if (uap->sbase == FSEEK_EOF)
3866254Sroot 		uap->off += fp->f_inode->i_size;
3876254Sroot 	fp->f_offset = uap->off;
3886254Sroot 	u.u_r.r_off = uap->off;
3896254Sroot }
3906254Sroot 
3916254Sroot /*
3926254Sroot  * Access system call
3936254Sroot  */
3946254Sroot saccess()
3956254Sroot {
3966254Sroot 	register svuid, svgid;
3976254Sroot 	register struct inode *ip;
3986254Sroot 	register struct a {
3996254Sroot 		char	*fname;
4006254Sroot 		int	fmode;
4016254Sroot 	} *uap;
4026254Sroot 
4036254Sroot 	uap = (struct a *)u.u_ap;
4046254Sroot 	svuid = u.u_uid;
4056254Sroot 	svgid = u.u_gid;
4066254Sroot 	u.u_uid = u.u_ruid;
4076254Sroot 	u.u_gid = u.u_rgid;
4086254Sroot 	ip = namei(uchar, 0, 1);
4096254Sroot 	if (ip != NULL) {
410*7701Ssam 		if (uap->fmode&FACCESS_READ && access(ip, IREAD))
411*7701Ssam 			goto done;
412*7701Ssam 		if (uap->fmode&FACCESS_WRITE && access(ip, IWRITE))
413*7701Ssam 			goto done;
414*7701Ssam 		if (uap->fmode&FACCESS_EXECUTE && access(ip, IEXEC))
415*7701Ssam 			goto done;
416*7701Ssam done:
4176254Sroot 		iput(ip);
4186254Sroot 	}
4196254Sroot 	u.u_uid = svuid;
4206254Sroot 	u.u_gid = svgid;
4216254Sroot }
4226254Sroot 
4236254Sroot /*
42437Sbill  * the fstat system call.
42537Sbill  */
42637Sbill fstat()
42737Sbill {
42837Sbill 	register struct file *fp;
42937Sbill 	register struct a {
430*7701Ssam 		int	fd;
43137Sbill 		struct stat *sb;
43237Sbill 	} *uap;
43337Sbill 
43437Sbill 	uap = (struct a *)u.u_ap;
435*7701Ssam 	fp = getf(uap->fd);
4364828Swnj 	if (fp == NULL)
43737Sbill 		return;
4387505Sroot 	if (fp->f_type == DTYPE_SOCKET)
4394891Swnj 		u.u_error = sostat(fp->f_socket, uap->sb);
4404828Swnj 	else
4414828Swnj 		stat1(fp->f_inode, uap->sb);
44237Sbill }
44337Sbill 
44437Sbill /*
4456574Smckusic  * Stat system call.  This version follows links.
44637Sbill  */
44737Sbill stat()
44837Sbill {
44937Sbill 	register struct inode *ip;
45037Sbill 	register struct a {
45137Sbill 		char	*fname;
45237Sbill 		struct stat *sb;
45337Sbill 	} *uap;
45437Sbill 
45537Sbill 	uap = (struct a *)u.u_ap;
4566423Sroot 	ip = namei(uchar, 0, 1);
4574828Swnj 	if (ip == NULL)
45837Sbill 		return;
4593624Sroot 	stat1(ip, uap->sb);
46037Sbill 	iput(ip);
46137Sbill }
46237Sbill 
46337Sbill /*
4646574Smckusic  * Lstat system call.  This version does not follow links.
4655992Swnj  */
4665992Swnj lstat()
4675992Swnj {
4685992Swnj 	register struct inode *ip;
4695992Swnj 	register struct a {
4705992Swnj 		char	*fname;
4715992Swnj 		struct stat *sb;
4725992Swnj 	} *uap;
4735992Swnj 
4745992Swnj 	uap = (struct a *)u.u_ap;
4756423Sroot 	ip = namei(uchar, 0, 0);
4765992Swnj 	if (ip == NULL)
4775992Swnj 		return;
4786153Ssam 	stat1(ip, uap->sb);
4795992Swnj 	iput(ip);
4805992Swnj }
4815992Swnj 
4825992Swnj /*
48337Sbill  * The basic routine for fstat and stat:
48437Sbill  * get the inode and pass appropriate parts back.
48537Sbill  */
4863624Sroot stat1(ip, ub)
4874828Swnj 	register struct inode *ip;
4884828Swnj 	struct stat *ub;
48937Sbill {
49037Sbill 	struct stat ds;
49137Sbill 
4921204Sbill 	IUPDAT(ip, &time, &time, 0);
49337Sbill 	/*
4947023Smckusick 	 * Copy from inode table
49537Sbill 	 */
49637Sbill 	ds.st_dev = ip->i_dev;
49737Sbill 	ds.st_ino = ip->i_number;
49837Sbill 	ds.st_mode = ip->i_mode;
49937Sbill 	ds.st_nlink = ip->i_nlink;
50037Sbill 	ds.st_uid = ip->i_uid;
50137Sbill 	ds.st_gid = ip->i_gid;
5026574Smckusic 	ds.st_rdev = (dev_t)ip->i_rdev;
5033624Sroot 	ds.st_size = ip->i_size;
5046574Smckusic 	ds.st_atime = ip->i_atime;
5056574Smckusic 	ds.st_mtime = ip->i_mtime;
5066574Smckusic 	ds.st_ctime = ip->i_ctime;
507*7701Ssam 	/* this doesn't belong here */
508*7701Ssam 	if ((ip->i_mode&IFMT) == IFBLK)
509*7701Ssam 		ds.st_blksize = BLKDEV_IOSIZE;
510*7701Ssam 	else if ((ip->i_mode&IFMT) == IFCHR)
511*7701Ssam 		ds.st_blksize = MAXBSIZE;
512*7701Ssam 	else
513*7701Ssam 		ds.st_blksize = ip->i_fs->fs_bsize;
51437Sbill 	if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
51537Sbill 		u.u_error = EFAULT;
51637Sbill }
51737Sbill 
51837Sbill /*
5195992Swnj  * Return target name of a symbolic link
52037Sbill  */
5215992Swnj readlink()
5225992Swnj {
5235992Swnj 	register struct inode *ip;
5245992Swnj 	register struct a {
5255992Swnj 		char	*name;
5265992Swnj 		char	*buf;
5275992Swnj 		int	count;
5285992Swnj 	} *uap;
5295992Swnj 
5305992Swnj 	ip = namei(uchar, 0, 0);
5315992Swnj 	if (ip == NULL)
5325992Swnj 		return;
5335992Swnj 	if ((ip->i_mode&IFMT) != IFLNK) {
5345992Swnj 		u.u_error = ENXIO;
5355992Swnj 		goto out;
5365992Swnj 	}
5375992Swnj 	uap = (struct a *)u.u_ap;
5385992Swnj 	u.u_offset = 0;
5395992Swnj 	u.u_base = uap->buf;
5405992Swnj 	u.u_count = uap->count;
5415992Swnj 	u.u_segflg = 0;
5425992Swnj 	readi(ip);
5435992Swnj out:
5445992Swnj 	iput(ip);
5455992Swnj 	u.u_r.r_val1 = uap->count - u.u_count;
5465992Swnj }
5475992Swnj 
5486254Sroot chmod()
5495992Swnj {
550*7701Ssam 	struct inode *ip;
551*7701Ssam 	struct a {
5526254Sroot 		char	*fname;
5536254Sroot 		int	fmode;
5545992Swnj 	} *uap;
5555992Swnj 
5565992Swnj 	uap = (struct a *)u.u_ap;
5576254Sroot 	if ((ip = owner(1)) == NULL)
5585992Swnj 		return;
559*7701Ssam 	chmod1(ip, uap->fmode);
560*7701Ssam }
5617439Sroot 
562*7701Ssam fchmod()
563*7701Ssam {
564*7701Ssam 	struct a {
565*7701Ssam 		int	fd;
566*7701Ssam 		int	fmode;
567*7701Ssam 	} *uap;
568*7701Ssam 	register struct inode *ip;
569*7701Ssam 	register struct file *fp;
570*7701Ssam 
571*7701Ssam 	uap = (struct a *)u.u_ap;
572*7701Ssam 	fp = getf(uap->fd);
573*7701Ssam 	if (fp == NULL)
574*7701Ssam 		return;
575*7701Ssam 	if (fp->f_type == DTYPE_SOCKET) {
576*7701Ssam 		u.u_error = EINVAL;
577*7701Ssam 		return;
5787439Sroot 	}
579*7701Ssam 	ip = fp->f_inode;
580*7701Ssam 	ilock(ip);
581*7701Ssam 	if (u.u_uid != ip->i_uid && !suser()) {
582*7701Ssam 		iunlock(ip);
583*7701Ssam 		return;
584*7701Ssam 	}
585*7701Ssam 	chmod1(ip, uap->fmode);
586*7701Ssam }
587*7701Ssam 
588*7701Ssam chmod1(ip, mode)
589*7701Ssam 	register struct inode *ip;
590*7701Ssam 	register int mode;
591*7701Ssam {
5926254Sroot 	ip->i_mode &= ~07777;
5937439Sroot 	if (u.u_uid) {
594*7701Ssam 		mode &= ~ISVTX;
5957439Sroot 		if (ip->i_gid >= NGRPS ||
5967439Sroot 		    (u.u_grps[ip->i_gid/(sizeof(int)*8)] &
5977439Sroot 		     (1 << ip->i_gid%(sizeof(int)*8))) == 0)
598*7701Ssam 			mode &= ~ISGID;
599*7701Ssam #ifdef MUSH
6007482Skre 		if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 &&
6017482Skre 		    (ip->i_mode & IFMT) != IFCHR)
602*7701Ssam 			mode &= ~u.u_cmask;
6037482Skre #endif
6047439Sroot 	}
605*7701Ssam 	ip->i_mode |= mode&07777;
6066254Sroot 	ip->i_flag |= ICHG;
6076254Sroot 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
6086254Sroot 		xrele(ip);
6095992Swnj 	iput(ip);
6105992Swnj }
6115992Swnj 
6126254Sroot chown()
61337Sbill {
614*7701Ssam 	struct inode *ip;
615*7701Ssam 	struct a {
6166254Sroot 		char	*fname;
6176254Sroot 		int	uid;
6186254Sroot 		int	gid;
61937Sbill 	} *uap;
62037Sbill 
62137Sbill 	uap = (struct a *)u.u_ap;
6226254Sroot 	if (!suser() || (ip = owner(0)) == NULL)
62337Sbill 		return;
624*7701Ssam 	chown1(ip, uap->uid, uap->gid);
625*7701Ssam }
6267439Sroot 
627*7701Ssam fchown()
628*7701Ssam {
629*7701Ssam 	struct a {
630*7701Ssam 		int	fd;
631*7701Ssam 		int	uid;
632*7701Ssam 		int	gid;
633*7701Ssam 	} *uap;
634*7701Ssam 	register struct inode *ip;
635*7701Ssam 	register struct file *fp;
636*7701Ssam 
637*7701Ssam 	uap = (struct a *)u.u_ap;
638*7701Ssam 	fp = getf(uap->fd);
639*7701Ssam 	if (fp == NULL)
640*7701Ssam 		return;
641*7701Ssam 	if (fp->f_type == DTYPE_SOCKET) {
642*7701Ssam 		u.u_error = EINVAL;
643*7701Ssam 		return;
6447439Sroot 	}
645*7701Ssam 	ip = fp->f_inode;
646*7701Ssam 	ilock(ip);
647*7701Ssam 	if (!suser()) {
648*7701Ssam 		iunlock(ip);
649*7701Ssam 		return;
650*7701Ssam 	}
651*7701Ssam 	chown1(ip, uap->uid, uap->gid);
652*7701Ssam }
653*7701Ssam 
654*7701Ssam /*
655*7701Ssam  * Perform chown operation on inode ip;
656*7701Ssam  * inode must be locked prior to call.
657*7701Ssam  */
658*7701Ssam chown1(ip, uid, gid)
659*7701Ssam 	register struct inode *ip;
660*7701Ssam 	int uid, gid;
661*7701Ssam {
662*7701Ssam #ifdef QUOTA
663*7701Ssam 	register long change;
664*7701Ssam 
6657439Sroot 	/*
6667482Skre 	 * This doesn't allow for holes in files (which hopefully don't
6677482Skre 	 * happen often in files that we chown), and is not accurate anyway
6687482Skre 	 * (eg: it totally ignores 3 level indir blk files - but hopefully
6697482Skre 	 * noone who can make a file that big will have a quota)
6707482Skre 	 */
671*7701Ssam 	if (ip->i_uid == uid)
6727482Skre 		change = 0;
6737482Skre 	else {
6747482Skre 		register struct fs *fs = ip->i_fs;
6757482Skre 
6767482Skre 		if (ip->i_size > (change = NDADDR * fs->fs_bsize)) {
6777482Skre 			register off_t size;
6787482Skre 
6797482Skre 			size = blkroundup(fs, ip->i_size) - change;
6807482Skre 			change += size;
6817482Skre 			change += fs->fs_bsize;
682*7701Ssam 			/* this assumes NIADDR <= 2 */
6837482Skre 			if (size > NINDIR(fs) * fs->fs_bsize)
6847482Skre 				change += fs->fs_bsize;
6857482Skre 		} else
6867482Skre 			change = fragroundup(fs, ip->i_size);
6877482Skre 		change /= DEV_BSIZE;
6887482Skre 	}
6897482Skre 	chkdq(ip, -change, 1);
6907482Skre 	chkiq(ip->i_dev, ip, ip->i_uid, 1);
6917482Skre 	dqrele(ip->i_dquot);
6927482Skre #endif
6937482Skre 	/*
694*7701Ssam 	 * keep uid/gid's in sane range -- no err,
695*7701Ssam 	 * so chown(file, uid, -1) will do something useful
6967439Sroot 	 */
697*7701Ssam 	if (uid >= 0 && uid <= 32767)	/* should have a constant */
698*7701Ssam 		ip->i_uid = uid;
699*7701Ssam 	if (gid >= 0 && gid <= 32767)	/* same here */
700*7701Ssam 		ip->i_gid = gid;
7016254Sroot 	ip->i_flag |= ICHG;
7026254Sroot 	if (u.u_ruid != 0)
7036254Sroot 		ip->i_mode &= ~(ISUID|ISGID);
704*7701Ssam #ifdef QUOTA
7057482Skre 	ip->i_dquot = inoquota(ip);
7067482Skre 	chkdq(ip, change, 1);
707*7701Ssam 	chkiq(ip->i_dev, NULL, uid, 1);
7087482Skre #endif
7096254Sroot 	iput(ip);
71037Sbill }
71137Sbill 
71237Sbill /*
7136254Sroot  * Set IUPD and IACC times on file.
7146254Sroot  * Can't set ICHG.
71537Sbill  */
7166254Sroot utime()
7174828Swnj {
71837Sbill 	register struct a {
7196254Sroot 		char	*fname;
7206254Sroot 		time_t	*tptr;
72137Sbill 	} *uap;
7226254Sroot 	register struct inode *ip;
7236254Sroot 	time_t tv[2];
72437Sbill 
72537Sbill 	uap = (struct a *)u.u_ap;
7266254Sroot 	if ((ip = owner(1)) == NULL)
72737Sbill 		return;
7286254Sroot 	if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
7296254Sroot 		u.u_error = EFAULT;
7306254Sroot 	} else {
7316254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
7326254Sroot 		iupdat(ip, &tv[0], &tv[1], 0);
73337Sbill 	}
73437Sbill 	iput(ip);
73537Sbill }
73637Sbill 
7376254Sroot sync()
73837Sbill {
73937Sbill 
7405416Swnj 	update(0);
74137Sbill }
7427535Sroot 
743*7701Ssam flock()
744*7701Ssam {
745*7701Ssam 	struct a {
746*7701Ssam 		int	fd;
747*7701Ssam 		int	how;
748*7701Ssam 	} *uap;
749*7701Ssam 	register struct file *fp;
750*7701Ssam 	register int cmd, flags;
751*7701Ssam 
752*7701Ssam 	uap = (struct a *)u.u_ap;
753*7701Ssam 	fp = getf(uap->fd);
754*7701Ssam 	if (fp == NULL)
755*7701Ssam 		return;
756*7701Ssam 	if (fp->f_type == DTYPE_SOCKET) {		/* XXX */
757*7701Ssam 		u.u_error = EINVAL;
758*7701Ssam 		return;
759*7701Ssam 	}
760*7701Ssam 	cmd = uap->how;
761*7701Ssam 	flags = u.u_pofile[uap->fd] & (RDLOCK|WRLOCK);
762*7701Ssam 	if (cmd&FUNLOCK) {
763*7701Ssam 		if (flags == 0) {
764*7701Ssam 			u.u_error = EINVAL;
765*7701Ssam 			return;
766*7701Ssam 		}
767*7701Ssam 		funlocki(fp->f_inode, flags);
768*7701Ssam 		u.u_pofile[uap->fd] &= ~(RDLOCK|WRLOCK);
769*7701Ssam 		return;
770*7701Ssam 	}
771*7701Ssam 	/*
772*7701Ssam 	 * No reason to write lock a file we've already
773*7701Ssam 	 * write locked, similarly with a read lock.
774*7701Ssam 	 */
775*7701Ssam 	if ((flags&WRLOCK) && (cmd&FWRLOCK) ||
776*7701Ssam 	    (flags&RDLOCK) && (cmd&FRDLOCK))
777*7701Ssam 		return;
778*7701Ssam 	u.u_pofile[uap->fd] = flocki(fp->f_inode, u.u_pofile[uap->fd], cmd);
779*7701Ssam }
780*7701Ssam 
781*7701Ssam truncate()
782*7701Ssam {
783*7701Ssam 	struct a {
784*7701Ssam 		char	*fname;
785*7701Ssam 		int	length;
786*7701Ssam 	} *uap;
787*7701Ssam 	struct inode *ip;
788*7701Ssam 
789*7701Ssam 	ip = namei(uchar, 0, 1);
790*7701Ssam 	if (ip == NULL)
791*7701Ssam 		return;
792*7701Ssam 	if (access(ip, IWRITE))
793*7701Ssam 		goto bad;
794*7701Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
795*7701Ssam 		u.u_error = EISDIR;
796*7701Ssam 		goto bad;
797*7701Ssam 	}
798*7701Ssam 	itrunc(ip, uap->length);
799*7701Ssam 	return;
800*7701Ssam bad:
801*7701Ssam 	iput(ip);
802*7701Ssam }
803*7701Ssam 
804*7701Ssam ftruncate()
805*7701Ssam {
806*7701Ssam 	struct a {
807*7701Ssam 		int	fd;
808*7701Ssam 		int	length;
809*7701Ssam 	} *uap;
810*7701Ssam 	struct inode *ip;
811*7701Ssam 	struct file *fp;
812*7701Ssam 
813*7701Ssam 	fp = getf(uap->fd);
814*7701Ssam 	if (fp == NULL)
815*7701Ssam 		return;
816*7701Ssam 	if (fp->f_type == DTYPE_SOCKET) {
817*7701Ssam 		u.u_error = EINVAL;
818*7701Ssam 		return;
819*7701Ssam 	}
820*7701Ssam 	if ((fp->f_flag&FWRITE) == 0) {
821*7701Ssam 		u.u_error = EINVAL;
822*7701Ssam 		return;
823*7701Ssam 	}
824*7701Ssam 	ip = fp->f_inode;
825*7701Ssam 	ilock(ip);
826*7701Ssam 	itrunc(ip, uap->length);
827*7701Ssam }
828*7701Ssam 
829*7701Ssam rename()
830*7701Ssam {
831*7701Ssam 	struct a {
832*7701Ssam 		char	*from;
833*7701Ssam 		char	*to;
834*7701Ssam 	} *uap;
835*7701Ssam 
836*7701Ssam }
837*7701Ssam 
8387535Sroot /*
8397535Sroot  * Make a new file.
8407535Sroot  */
8417535Sroot struct inode *
8427535Sroot maknode(mode)
8437535Sroot 	int mode;
8447535Sroot {
8457535Sroot 	register struct inode *ip;
8467535Sroot 	ino_t ipref;
8477535Sroot 
8487535Sroot 	if ((mode & IFMT) == IFDIR)
8497535Sroot 		ipref = dirpref(u.u_pdir->i_fs);
8507535Sroot 	else
8517535Sroot 		ipref = u.u_pdir->i_number;
8527535Sroot 	ip = ialloc(u.u_pdir, ipref, mode);
8537535Sroot 	if (ip == NULL) {
8547535Sroot 		iput(u.u_pdir);
855*7701Ssam 		return (NULL);
8567535Sroot 	}
857*7701Ssam #ifdef QUOTA
8587535Sroot 	if (ip->i_dquot != NODQUOT)
8597535Sroot 		panic("maknode: dquot");
8607535Sroot #endif
8617535Sroot 	ip->i_flag |= IACC|IUPD|ICHG;
8627535Sroot 	if ((mode & IFMT) == 0)
8637535Sroot 		mode |= IFREG;
8647535Sroot 	ip->i_mode = mode & ~u.u_cmask;
8657535Sroot 	ip->i_nlink = 1;
8667535Sroot 	ip->i_uid = u.u_uid;
8677535Sroot 	ip->i_gid = u.u_pdir->i_gid;
868*7701Ssam #ifdef QUOTA
8697535Sroot 	ip->i_dquot = inoquota(ip);
8707535Sroot #endif
8717535Sroot 
8727535Sroot 	/*
8737535Sroot 	 * Make sure inode goes to disk before directory entry.
8747535Sroot 	 */
8757535Sroot 	iupdat(ip, &time, &time, 1);
8767535Sroot 	direnter(ip);
8777535Sroot 	if (u.u_error) {
8787535Sroot 		/*
8797535Sroot 		 * write error occurred trying to update directory
8807535Sroot 		 * so must deallocate the inode
8817535Sroot 		 */
8827535Sroot 		ip->i_nlink = 0;
8837535Sroot 		ip->i_flag |= ICHG;
8847535Sroot 		iput(ip);
885*7701Ssam 		return (NULL);
8867535Sroot 	}
887*7701Ssam 	return (ip);
8887535Sroot }
889