xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 16694)
1*16694Smckusick /*	vfs_syscalls.c	6.11	84/07/08	*/
237Sbill 
337Sbill #include "../h/param.h"
437Sbill #include "../h/systm.h"
537Sbill #include "../h/dir.h"
637Sbill #include "../h/user.h"
78040Sroot #include "../h/kernel.h"
86254Sroot #include "../h/file.h"
96574Smckusic #include "../h/stat.h"
1037Sbill #include "../h/inode.h"
116574Smckusic #include "../h/fs.h"
126254Sroot #include "../h/buf.h"
136254Sroot #include "../h/proc.h"
147482Skre #include "../h/quota.h"
157826Sroot #include "../h/uio.h"
167826Sroot #include "../h/socket.h"
178632Sroot #include "../h/socketvar.h"
1812756Ssam #include "../h/mount.h"
1937Sbill 
2012756Ssam extern	struct fileops inodeops;
2112756Ssam struct	file *getinode();
2212756Ssam 
239167Ssam /*
249167Ssam  * Change current working directory (``.'').
259167Ssam  */
266254Sroot chdir()
276254Sroot {
286254Sroot 
296254Sroot 	chdirec(&u.u_cdir);
306254Sroot }
316254Sroot 
329167Ssam /*
339167Ssam  * Change notion of root (``/'') directory.
349167Ssam  */
356254Sroot chroot()
366254Sroot {
376254Sroot 
386254Sroot 	if (suser())
396254Sroot 		chdirec(&u.u_rdir);
406254Sroot }
416254Sroot 
429167Ssam /*
439167Ssam  * Common routine for chroot and chdir.
449167Ssam  */
456254Sroot chdirec(ipp)
467701Ssam 	register struct inode **ipp;
476254Sroot {
486254Sroot 	register struct inode *ip;
496254Sroot 	struct a {
506254Sroot 		char	*fname;
51*16694Smckusick 	} *uap = (struct a *)u.u_ap;
52*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
536254Sroot 
54*16694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
55*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
56*16694Smckusick 	ndp->ni_dirp = uap->fname;
57*16694Smckusick 	ip = namei(ndp);
589167Ssam 	if (ip == NULL)
596254Sroot 		return;
609167Ssam 	if ((ip->i_mode&IFMT) != IFDIR) {
616254Sroot 		u.u_error = ENOTDIR;
626254Sroot 		goto bad;
636254Sroot 	}
649167Ssam 	if (access(ip, IEXEC))
656254Sroot 		goto bad;
6616664Smckusick 	IUNLOCK(ip);
677142Smckusick 	if (*ipp)
687142Smckusick 		irele(*ipp);
696254Sroot 	*ipp = ip;
706254Sroot 	return;
716254Sroot 
726254Sroot bad:
736254Sroot 	iput(ip);
746254Sroot }
756254Sroot 
7637Sbill /*
776254Sroot  * Open system call.
786254Sroot  */
796254Sroot open()
806254Sroot {
8112756Ssam 	struct a {
826254Sroot 		char	*fname;
837701Ssam 		int	mode;
8412756Ssam 		int	crtmode;
8512756Ssam 	} *uap = (struct a *) u.u_ap;
866254Sroot 
87*16694Smckusick 	copen(uap->mode-FOPEN, uap->crtmode, uap->fname);
886254Sroot }
896254Sroot 
906254Sroot /*
916254Sroot  * Creat system call.
926254Sroot  */
9312756Ssam creat()
946254Sroot {
9512756Ssam 	struct a {
966254Sroot 		char	*fname;
976254Sroot 		int	fmode;
9812756Ssam 	} *uap = (struct a *)u.u_ap;
996254Sroot 
100*16694Smckusick 	copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname);
1016254Sroot }
1026254Sroot 
1036254Sroot /*
1046254Sroot  * Common code for open and creat.
10512756Ssam  * Check permissions, allocate an open file structure,
10612756Ssam  * and call the device open routine if any.
1076254Sroot  */
108*16694Smckusick copen(mode, arg, fname)
10912756Ssam 	register int mode;
11012756Ssam 	int arg;
111*16694Smckusick 	caddr_t fname;
11212756Ssam {
1136254Sroot 	register struct inode *ip;
1146254Sroot 	register struct file *fp;
115*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
11612756Ssam 	int i;
1176254Sroot 
11812756Ssam #ifdef notdef
11912756Ssam 	if ((mode&(FREAD|FWRITE)) == 0) {
12012756Ssam 		u.u_error = EINVAL;
12112756Ssam 		return;
12212756Ssam 	}
12312756Ssam #endif
124*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
125*16694Smckusick 	ndp->ni_dirp = fname;
12612756Ssam 	if (mode&FCREAT) {
127*16694Smckusick 		ndp->ni_nameiop = CREATE | FOLLOW;
128*16694Smckusick 		ip = namei(ndp);
12912756Ssam 		if (ip == NULL) {
13012756Ssam 			if (u.u_error)
13112756Ssam 				return;
132*16694Smckusick 			ip = maknode(arg&07777&(~ISVTX), ndp);
13312756Ssam 			if (ip == NULL)
13412756Ssam 				return;
13512756Ssam 			mode &= ~FTRUNC;
13612756Ssam 		} else {
13712756Ssam 			if (mode&FEXCL) {
13812756Ssam 				u.u_error = EEXIST;
13912756Ssam 				iput(ip);
14012756Ssam 				return;
14112756Ssam 			}
14212756Ssam 			mode &= ~FCREAT;
14312756Ssam 		}
14412756Ssam 	} else {
145*16694Smckusick 		ndp->ni_nameiop = LOOKUP | FOLLOW;
146*16694Smckusick 		ip = namei(ndp);
14712756Ssam 		if (ip == NULL)
14812756Ssam 			return;
14912756Ssam 	}
15012756Ssam 	if ((ip->i_mode & IFMT) == IFSOCK) {
15112756Ssam 		u.u_error = EOPNOTSUPP;
15212756Ssam 		goto bad;
15312756Ssam 	}
15412756Ssam 	if ((mode&FCREAT) == 0) {
1556254Sroot 		if (mode&FREAD)
1567701Ssam 			if (access(ip, IREAD))
1577701Ssam 				goto bad;
15816032Skarels 		if (mode&(FWRITE|FTRUNC)) {
1597701Ssam 			if (access(ip, IWRITE))
1607701Ssam 				goto bad;
1617701Ssam 			if ((ip->i_mode&IFMT) == IFDIR) {
1626254Sroot 				u.u_error = EISDIR;
1637701Ssam 				goto bad;
1647701Ssam 			}
1656254Sroot 		}
1666254Sroot 	}
16712756Ssam 	fp = falloc();
16812756Ssam 	if (fp == NULL)
16912756Ssam 		goto bad;
17012756Ssam 	if (mode&FTRUNC)
1719167Ssam 		itrunc(ip, (u_long)0);
17216664Smckusick 	IUNLOCK(ip);
17312756Ssam 	fp->f_flag = mode&FMASK;
17412756Ssam 	fp->f_type = DTYPE_INODE;
17512756Ssam 	fp->f_ops = &inodeops;
17612756Ssam 	fp->f_data = (caddr_t)ip;
1776254Sroot 	i = u.u_r.r_val1;
17812756Ssam 	if (setjmp(&u.u_qsave)) {
17912756Ssam 		if (u.u_error == 0)
18012756Ssam 			u.u_error = EINTR;
18112756Ssam 		u.u_ofile[i] = NULL;
18212756Ssam 		closef(fp);
18312756Ssam 		return;
18412756Ssam 	}
1858559Sroot 	u.u_error = openi(ip, mode);
18612756Ssam 	if (u.u_error == 0)
1876254Sroot 		return;
1886254Sroot 	u.u_ofile[i] = NULL;
1896254Sroot 	fp->f_count--;
1907142Smckusick 	irele(ip);
1917701Ssam 	return;
1927701Ssam bad:
1937701Ssam 	iput(ip);
1946254Sroot }
1956254Sroot 
1966254Sroot /*
1976254Sroot  * Mknod system call
1986254Sroot  */
1996254Sroot mknod()
2006254Sroot {
2016254Sroot 	register struct inode *ip;
2026254Sroot 	register struct a {
2036254Sroot 		char	*fname;
2046254Sroot 		int	fmode;
2056254Sroot 		int	dev;
206*16694Smckusick 	} *uap = (struct a *)u.u_ap;
207*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
2086254Sroot 
20912756Ssam 	if (!suser())
21012756Ssam 		return;
211*16694Smckusick 	ndp->ni_nameiop = CREATE;
212*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
213*16694Smckusick 	ndp->ni_dirp = uap->fname;
214*16694Smckusick 	ip = namei(ndp);
21512756Ssam 	if (ip != NULL) {
21612756Ssam 		u.u_error = EEXIST;
21712756Ssam 		goto out;
2186254Sroot 	}
2196254Sroot 	if (u.u_error)
2206254Sroot 		return;
221*16694Smckusick 	ip = maknode(uap->fmode, ndp);
2226254Sroot 	if (ip == NULL)
2236254Sroot 		return;
22412756Ssam 	switch (ip->i_mode & IFMT) {
22512756Ssam 
22615093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
22712756Ssam 	case IFCHR:
22812756Ssam 	case IFBLK:
22912756Ssam 		if (uap->dev) {
23012756Ssam 			/*
23112756Ssam 			 * Want to be able to use this to make badblock
23212756Ssam 			 * inodes, so don't truncate the dev number.
23312756Ssam 			 */
23412756Ssam 			ip->i_rdev = uap->dev;
23512756Ssam 			ip->i_flag |= IACC|IUPD|ICHG;
23612756Ssam 		}
2376254Sroot 	}
2386254Sroot 
2396254Sroot out:
2406254Sroot 	iput(ip);
2416254Sroot }
2426254Sroot 
2436254Sroot /*
2446254Sroot  * link system call
2456254Sroot  */
2466254Sroot link()
2476254Sroot {
2486254Sroot 	register struct inode *ip, *xp;
2496254Sroot 	register struct a {
2506254Sroot 		char	*target;
2516254Sroot 		char	*linkname;
252*16694Smckusick 	} *uap = (struct a *)u.u_ap;
253*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
2546254Sroot 
255*16694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
256*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
257*16694Smckusick 	ndp->ni_dirp = uap->target;
258*16694Smckusick 	ip = namei(ndp);	/* well, this routine is doomed anyhow */
2596254Sroot 	if (ip == NULL)
2606254Sroot 		return;
2619167Ssam 	if ((ip->i_mode&IFMT) == IFDIR && !suser()) {
2627439Sroot 		iput(ip);
2637439Sroot 		return;
2647439Sroot 	}
2656254Sroot 	ip->i_nlink++;
2666254Sroot 	ip->i_flag |= ICHG;
2678673Sroot 	iupdat(ip, &time, &time, 1);
26816664Smckusick 	IUNLOCK(ip);
269*16694Smckusick 	ndp->ni_nameiop = CREATE;
270*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
271*16694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
272*16694Smckusick 	xp = namei(ndp);
2736254Sroot 	if (xp != NULL) {
2746254Sroot 		u.u_error = EEXIST;
2756254Sroot 		iput(xp);
2766254Sroot 		goto out;
2776254Sroot 	}
2786254Sroot 	if (u.u_error)
2796254Sroot 		goto out;
280*16694Smckusick 	if (ndp->ni_pdir->i_dev != ip->i_dev) {
281*16694Smckusick 		iput(ndp->ni_pdir);
2826254Sroot 		u.u_error = EXDEV;
2836254Sroot 		goto out;
2846254Sroot 	}
285*16694Smckusick 	u.u_error = direnter(ip, ndp);
2866254Sroot out:
2876254Sroot 	if (u.u_error) {
2886254Sroot 		ip->i_nlink--;
2896254Sroot 		ip->i_flag |= ICHG;
2906254Sroot 	}
2917142Smckusick 	irele(ip);
2926254Sroot }
2936254Sroot 
2946254Sroot /*
2956254Sroot  * symlink -- make a symbolic link
2966254Sroot  */
2976254Sroot symlink()
2986254Sroot {
2996254Sroot 	register struct a {
3006254Sroot 		char	*target;
3016254Sroot 		char	*linkname;
302*16694Smckusick 	} *uap = (struct a *)u.u_ap;
3036254Sroot 	register struct inode *ip;
3046254Sroot 	register char *tp;
3056254Sroot 	register c, nc;
306*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
3076254Sroot 
3086254Sroot 	tp = uap->target;
3096254Sroot 	nc = 0;
3106254Sroot 	while (c = fubyte(tp)) {
3116254Sroot 		if (c < 0) {
3126254Sroot 			u.u_error = EFAULT;
3136254Sroot 			return;
3146254Sroot 		}
3156254Sroot 		tp++;
3166254Sroot 		nc++;
3176254Sroot 	}
318*16694Smckusick 	ndp->ni_nameiop = CREATE;
319*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
320*16694Smckusick 	ndp->ni_dirp = uap->linkname;
321*16694Smckusick 	ip = namei(ndp);
3226254Sroot 	if (ip) {
3236254Sroot 		iput(ip);
3246254Sroot 		u.u_error = EEXIST;
3256254Sroot 		return;
3266254Sroot 	}
3276254Sroot 	if (u.u_error)
3286254Sroot 		return;
329*16694Smckusick 	ip = maknode(IFLNK | 0777, ndp);
3306254Sroot 	if (ip == NULL)
3316254Sroot 		return;
3327826Sroot 	u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0);
3339167Ssam 	/* handle u.u_error != 0 */
3346254Sroot 	iput(ip);
3356254Sroot }
3366254Sroot 
3376254Sroot /*
3386254Sroot  * Unlink system call.
3396254Sroot  * Hard to avoid races here, especially
3406254Sroot  * in unlinking directories.
3416254Sroot  */
3426254Sroot unlink()
3436254Sroot {
3446254Sroot 	struct a {
3456254Sroot 		char	*fname;
346*16694Smckusick 	} *uap = (struct a *)u.u_ap;
3479167Ssam 	register struct inode *ip, *dp;
348*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
3496254Sroot 
350*16694Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT;
351*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
352*16694Smckusick 	ndp->ni_dirp = uap->fname;
353*16694Smckusick 	ip = namei(ndp);
3549167Ssam 	if (ip == NULL)
3556254Sroot 		return;
356*16694Smckusick 	dp = ndp->ni_pdir;
3579167Ssam 	if ((ip->i_mode&IFMT) == IFDIR && !suser())
3586254Sroot 		goto out;
3596254Sroot 	/*
3606254Sroot 	 * Don't unlink a mounted file.
3616254Sroot 	 */
3629167Ssam 	if (ip->i_dev != dp->i_dev) {
3636254Sroot 		u.u_error = EBUSY;
3646254Sroot 		goto out;
3656254Sroot 	}
3666254Sroot 	if (ip->i_flag&ITEXT)
3676254Sroot 		xrele(ip);	/* try once to free text */
368*16694Smckusick 	if (dirremove(ndp)) {
3697535Sroot 		ip->i_nlink--;
3707535Sroot 		ip->i_flag |= ICHG;
3716254Sroot 	}
3726254Sroot out:
3739167Ssam 	if (dp == ip)
3747142Smckusick 		irele(ip);
3757142Smckusick 	else
3767142Smckusick 		iput(ip);
3779167Ssam 	iput(dp);
3786254Sroot }
3796254Sroot 
3806254Sroot /*
3816254Sroot  * Seek system call
3826254Sroot  */
3838040Sroot lseek()
3846254Sroot {
3856254Sroot 	register struct file *fp;
3866254Sroot 	register struct a {
3877701Ssam 		int	fd;
3886254Sroot 		off_t	off;
3896254Sroot 		int	sbase;
390*16694Smckusick 	} *uap = (struct a *)u.u_ap;
3916254Sroot 
39216540Ssam 	GETF(fp, uap->fd);
39316540Ssam 	if (fp->f_type != DTYPE_INODE) {
39416540Ssam 		u.u_error = ESPIPE;
3956254Sroot 		return;
39616540Ssam 	}
39713878Ssam 	switch (uap->sbase) {
39813878Ssam 
39913878Ssam 	case L_INCR:
40013878Ssam 		fp->f_offset += uap->off;
40113878Ssam 		break;
40213878Ssam 
40313878Ssam 	case L_XTND:
40413878Ssam 		fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
40513878Ssam 		break;
40613878Ssam 
40713878Ssam 	case L_SET:
40813878Ssam 		fp->f_offset = uap->off;
40913878Ssam 		break;
41013878Ssam 
41113878Ssam 	default:
41213878Ssam 		u.u_error = EINVAL;
41313878Ssam 		return;
41413878Ssam 	}
41513878Ssam 	u.u_r.r_off = fp->f_offset;
4166254Sroot }
4176254Sroot 
4186254Sroot /*
4196254Sroot  * Access system call
4206254Sroot  */
4216254Sroot saccess()
4226254Sroot {
4236254Sroot 	register svuid, svgid;
4246254Sroot 	register struct inode *ip;
4256254Sroot 	register struct a {
4266254Sroot 		char	*fname;
4276254Sroot 		int	fmode;
428*16694Smckusick 	} *uap = (struct a *)u.u_ap;
429*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
4306254Sroot 
4316254Sroot 	svuid = u.u_uid;
4326254Sroot 	svgid = u.u_gid;
4336254Sroot 	u.u_uid = u.u_ruid;
4346254Sroot 	u.u_gid = u.u_rgid;
435*16694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
436*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
437*16694Smckusick 	ndp->ni_dirp = uap->fname;
438*16694Smckusick 	ip = namei(ndp);
4396254Sroot 	if (ip != NULL) {
44012756Ssam 		if ((uap->fmode&R_OK) && access(ip, IREAD))
4417701Ssam 			goto done;
44212756Ssam 		if ((uap->fmode&W_OK) && access(ip, IWRITE))
4437701Ssam 			goto done;
44412756Ssam 		if ((uap->fmode&X_OK) && access(ip, IEXEC))
4457701Ssam 			goto done;
4467701Ssam done:
4476254Sroot 		iput(ip);
4486254Sroot 	}
4496254Sroot 	u.u_uid = svuid;
4506254Sroot 	u.u_gid = svgid;
4516254Sroot }
4526254Sroot 
4536254Sroot /*
4546574Smckusic  * Stat system call.  This version follows links.
45537Sbill  */
45637Sbill stat()
45737Sbill {
45837Sbill 
459*16694Smckusick 	stat1(FOLLOW);
46037Sbill }
46137Sbill 
46237Sbill /*
4636574Smckusic  * Lstat system call.  This version does not follow links.
4645992Swnj  */
4655992Swnj lstat()
4665992Swnj {
46712756Ssam 
468*16694Smckusick 	stat1(NOFOLLOW);
46912756Ssam }
47012756Ssam 
47112756Ssam stat1(follow)
47212756Ssam 	int follow;
47312756Ssam {
4745992Swnj 	register struct inode *ip;
4755992Swnj 	register struct a {
4765992Swnj 		char	*fname;
47712756Ssam 		struct stat *ub;
478*16694Smckusick 	} *uap = (struct a *)u.u_ap;
47912756Ssam 	struct stat sb;
480*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
4815992Swnj 
482*16694Smckusick 	ndp->ni_nameiop = LOOKUP | follow;
483*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
484*16694Smckusick 	ndp->ni_dirp = uap->fname;
485*16694Smckusick 	ip = namei(ndp);
4865992Swnj 	if (ip == NULL)
4875992Swnj 		return;
48813043Ssam 	(void) ino_stat(ip, &sb);
4895992Swnj 	iput(ip);
49012756Ssam 	u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
4915992Swnj }
4925992Swnj 
4935992Swnj /*
4945992Swnj  * Return target name of a symbolic link
49537Sbill  */
4965992Swnj readlink()
4975992Swnj {
4985992Swnj 	register struct inode *ip;
4995992Swnj 	register struct a {
5005992Swnj 		char	*name;
5015992Swnj 		char	*buf;
5025992Swnj 		int	count;
5037826Sroot 	} *uap = (struct a *)u.u_ap;
504*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
5057826Sroot 	int resid;
5065992Swnj 
507*16694Smckusick 	ndp->ni_nameiop = LOOKUP;
508*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
509*16694Smckusick 	ndp->ni_dirp = uap->name;
510*16694Smckusick 	ip = namei(ndp);
5115992Swnj 	if (ip == NULL)
5125992Swnj 		return;
5135992Swnj 	if ((ip->i_mode&IFMT) != IFLNK) {
5145992Swnj 		u.u_error = ENXIO;
5155992Swnj 		goto out;
5165992Swnj 	}
5177826Sroot 	u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid);
5185992Swnj out:
5195992Swnj 	iput(ip);
5207826Sroot 	u.u_r.r_val1 = uap->count - resid;
5215992Swnj }
5225992Swnj 
5239167Ssam /*
5249167Ssam  * Change mode of a file given path name.
5259167Ssam  */
5266254Sroot chmod()
5275992Swnj {
5287701Ssam 	struct inode *ip;
5297701Ssam 	struct a {
5306254Sroot 		char	*fname;
5316254Sroot 		int	fmode;
532*16694Smckusick 	} *uap = (struct a *)u.u_ap;
5335992Swnj 
534*16694Smckusick 	if ((ip = owner(uap->fname, FOLLOW)) == NULL)
5355992Swnj 		return;
5367701Ssam 	chmod1(ip, uap->fmode);
5379167Ssam 	iput(ip);
5387701Ssam }
5397439Sroot 
5409167Ssam /*
5419167Ssam  * Change mode of a file given a file descriptor.
5429167Ssam  */
5437701Ssam fchmod()
5447701Ssam {
5457701Ssam 	struct a {
5467701Ssam 		int	fd;
5477701Ssam 		int	fmode;
548*16694Smckusick 	} *uap = (struct a *)u.u_ap;
5497701Ssam 	register struct inode *ip;
5507701Ssam 	register struct file *fp;
5517701Ssam 
55212756Ssam 	fp = getinode(uap->fd);
5537701Ssam 	if (fp == NULL)
5547701Ssam 		return;
55512756Ssam 	ip = (struct inode *)fp->f_data;
5569167Ssam 	if (u.u_uid != ip->i_uid && !suser())
5579167Ssam 		return;
55816664Smckusick 	ILOCK(ip);
5597701Ssam 	chmod1(ip, uap->fmode);
56016664Smckusick 	IUNLOCK(ip);
5617701Ssam }
5627701Ssam 
5639167Ssam /*
5649167Ssam  * Change the mode on a file.
5659167Ssam  * Inode must be locked before calling.
5669167Ssam  */
5677701Ssam chmod1(ip, mode)
5687701Ssam 	register struct inode *ip;
5697701Ssam 	register int mode;
5707701Ssam {
5717868Sroot 
5726254Sroot 	ip->i_mode &= ~07777;
5737439Sroot 	if (u.u_uid) {
5747701Ssam 		mode &= ~ISVTX;
57511811Ssam 		if (!groupmember(ip->i_gid))
57611811Ssam 			mode &= ~ISGID;
5777439Sroot 	}
5787701Ssam 	ip->i_mode |= mode&07777;
5796254Sroot 	ip->i_flag |= ICHG;
5806254Sroot 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
5816254Sroot 		xrele(ip);
5825992Swnj }
5835992Swnj 
5849167Ssam /*
5859167Ssam  * Set ownership given a path name.
5869167Ssam  */
5876254Sroot chown()
58837Sbill {
5897701Ssam 	struct inode *ip;
5907701Ssam 	struct a {
5916254Sroot 		char	*fname;
5926254Sroot 		int	uid;
5936254Sroot 		int	gid;
594*16694Smckusick 	} *uap = (struct a *)u.u_ap;
59537Sbill 
596*16694Smckusick 	if (!suser() || (ip = owner(uap->fname, NOFOLLOW)) == NULL)
59737Sbill 		return;
59811811Ssam 	u.u_error = chown1(ip, uap->uid, uap->gid);
5999167Ssam 	iput(ip);
6007701Ssam }
6017439Sroot 
6029167Ssam /*
6039167Ssam  * Set ownership given a file descriptor.
6049167Ssam  */
6057701Ssam fchown()
6067701Ssam {
6077701Ssam 	struct a {
6087701Ssam 		int	fd;
6097701Ssam 		int	uid;
6107701Ssam 		int	gid;
611*16694Smckusick 	} *uap = (struct a *)u.u_ap;
6127701Ssam 	register struct inode *ip;
6137701Ssam 	register struct file *fp;
6147701Ssam 
61512756Ssam 	fp = getinode(uap->fd);
6167701Ssam 	if (fp == NULL)
6177701Ssam 		return;
61812756Ssam 	ip = (struct inode *)fp->f_data;
61911821Ssam 	if (!suser())
6209167Ssam 		return;
62116664Smckusick 	ILOCK(ip);
62211811Ssam 	u.u_error = chown1(ip, uap->uid, uap->gid);
62316664Smckusick 	IUNLOCK(ip);
6247701Ssam }
6257701Ssam 
6267701Ssam /*
6277701Ssam  * Perform chown operation on inode ip;
6287701Ssam  * inode must be locked prior to call.
6297701Ssam  */
6307701Ssam chown1(ip, uid, gid)
6317701Ssam 	register struct inode *ip;
6327701Ssam 	int uid, gid;
6337701Ssam {
6347701Ssam #ifdef QUOTA
6357701Ssam 	register long change;
63611811Ssam #endif
6377701Ssam 
63811811Ssam 	if (uid == -1)
63911811Ssam 		uid = ip->i_uid;
64011811Ssam 	if (gid == -1)
64111811Ssam 		gid = ip->i_gid;
64211811Ssam #ifdef QUOTA
64314385Ssam 	if (ip->i_uid == uid)		/* this just speeds things a little */
6447482Skre 		change = 0;
64512646Ssam 	else
64612646Ssam 		change = ip->i_blocks;
64712646Ssam 	(void) chkdq(ip, -change, 1);
64812646Ssam 	(void) chkiq(ip->i_dev, ip, ip->i_uid, 1);
6497482Skre 	dqrele(ip->i_dquot);
6507482Skre #endif
65111811Ssam 	ip->i_uid = uid;
65211811Ssam 	ip->i_gid = gid;
6536254Sroot 	ip->i_flag |= ICHG;
6546254Sroot 	if (u.u_ruid != 0)
6556254Sroot 		ip->i_mode &= ~(ISUID|ISGID);
6567701Ssam #ifdef QUOTA
6577482Skre 	ip->i_dquot = inoquota(ip);
65812646Ssam 	(void) chkdq(ip, change, 1);
65912646Ssam 	(void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
66012646Ssam 	return (u.u_error);		/* should == 0 ALWAYS !! */
66112646Ssam #else
66212646Ssam 	return (0);
6637482Skre #endif
66437Sbill }
66537Sbill 
66611811Ssam utimes()
66711811Ssam {
66811811Ssam 	register struct a {
66911811Ssam 		char	*fname;
67011811Ssam 		struct	timeval *tptr;
67111811Ssam 	} *uap = (struct a *)u.u_ap;
67211811Ssam 	register struct inode *ip;
67311811Ssam 	struct timeval tv[2];
67411811Ssam 
675*16694Smckusick 	if ((ip = owner(uap->fname, FOLLOW)) == NULL)
67611811Ssam 		return;
67711811Ssam 	u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
67811811Ssam 	if (u.u_error == 0) {
67911811Ssam 		ip->i_flag |= IACC|IUPD|ICHG;
68011811Ssam 		iupdat(ip, &tv[0], &tv[1], 0);
68111811Ssam 	}
68211811Ssam 	iput(ip);
68311811Ssam }
68411811Ssam 
6859167Ssam /*
6869167Ssam  * Flush any pending I/O.
6879167Ssam  */
6886254Sroot sync()
68937Sbill {
69037Sbill 
6918673Sroot 	update();
69237Sbill }
6937535Sroot 
6949167Ssam /*
6959167Ssam  * Truncate a file given its path name.
6969167Ssam  */
6977701Ssam truncate()
6987701Ssam {
6997701Ssam 	struct a {
7007701Ssam 		char	*fname;
7019167Ssam 		u_long	length;
7027826Sroot 	} *uap = (struct a *)u.u_ap;
7037701Ssam 	struct inode *ip;
704*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
7057701Ssam 
706*16694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
707*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
708*16694Smckusick 	ndp->ni_dirp = uap->fname;
709*16694Smckusick 	ip = namei(ndp);
7107701Ssam 	if (ip == NULL)
7117701Ssam 		return;
7127701Ssam 	if (access(ip, IWRITE))
7137701Ssam 		goto bad;
7147701Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
7157701Ssam 		u.u_error = EISDIR;
7167701Ssam 		goto bad;
7177701Ssam 	}
7187701Ssam 	itrunc(ip, uap->length);
7197701Ssam bad:
7207701Ssam 	iput(ip);
7217701Ssam }
7227701Ssam 
7239167Ssam /*
7249167Ssam  * Truncate a file given a file descriptor.
7259167Ssam  */
7267701Ssam ftruncate()
7277701Ssam {
7287701Ssam 	struct a {
7297701Ssam 		int	fd;
7309167Ssam 		u_long	length;
7317826Sroot 	} *uap = (struct a *)u.u_ap;
7327701Ssam 	struct inode *ip;
7337701Ssam 	struct file *fp;
7347701Ssam 
73512756Ssam 	fp = getinode(uap->fd);
7367701Ssam 	if (fp == NULL)
7377701Ssam 		return;
7387701Ssam 	if ((fp->f_flag&FWRITE) == 0) {
7397701Ssam 		u.u_error = EINVAL;
7407701Ssam 		return;
7417701Ssam 	}
74212756Ssam 	ip = (struct inode *)fp->f_data;
74316664Smckusick 	ILOCK(ip);
7447701Ssam 	itrunc(ip, uap->length);
74516664Smckusick 	IUNLOCK(ip);
7467701Ssam }
7477701Ssam 
7489167Ssam /*
7499167Ssam  * Synch an open file.
7509167Ssam  */
7519167Ssam fsync()
7529167Ssam {
7539167Ssam 	struct a {
7549167Ssam 		int	fd;
7559167Ssam 	} *uap = (struct a *)u.u_ap;
7569167Ssam 	struct inode *ip;
7579167Ssam 	struct file *fp;
7589167Ssam 
75912756Ssam 	fp = getinode(uap->fd);
7609167Ssam 	if (fp == NULL)
7619167Ssam 		return;
76212756Ssam 	ip = (struct inode *)fp->f_data;
76316664Smckusick 	ILOCK(ip);
7649167Ssam 	syncip(ip);
76516664Smckusick 	IUNLOCK(ip);
7669167Ssam }
7679167Ssam 
7689167Ssam /*
7699167Ssam  * Rename system call.
7709167Ssam  * 	rename("foo", "bar");
7719167Ssam  * is essentially
7729167Ssam  *	unlink("bar");
7739167Ssam  *	link("foo", "bar");
7749167Ssam  *	unlink("foo");
7759167Ssam  * but ``atomically''.  Can't do full commit without saving state in the
7769167Ssam  * inode on disk which isn't feasible at this time.  Best we can do is
7779167Ssam  * always guarantee the target exists.
7789167Ssam  *
7799167Ssam  * Basic algorithm is:
7809167Ssam  *
7819167Ssam  * 1) Bump link count on source while we're linking it to the
7829167Ssam  *    target.  This also insure the inode won't be deleted out
7839167Ssam  *    from underneath us while we work.
7849167Ssam  * 2) Link source to destination.  If destination already exists,
7859167Ssam  *    delete it first.
7869167Ssam  * 3) Unlink source reference to inode if still around.
7879167Ssam  * 4) If a directory was moved and the parent of the destination
7889167Ssam  *    is different from the source, patch the ".." entry in the
7899167Ssam  *    directory.
7909167Ssam  *
7919167Ssam  * Source and destination must either both be directories, or both
7929167Ssam  * not be directories.  If target is a directory, it must be empty.
7939167Ssam  */
7947701Ssam rename()
7957701Ssam {
7967701Ssam 	struct a {
7977701Ssam 		char	*from;
7987701Ssam 		char	*to;
799*16694Smckusick 	} *uap = (struct a *)u.u_ap;
8009167Ssam 	register struct inode *ip, *xp, *dp;
80116655Smckusick 	struct inode *zp;
8029167Ssam 	int oldparent, parentdifferent, doingdirectory;
803*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
80410051Ssam 	int error = 0;
8057701Ssam 
806*16694Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT;
807*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
808*16694Smckusick 	ndp->ni_dirp = uap->from;
809*16694Smckusick 	ip = namei(ndp);
8109167Ssam 	if (ip == NULL)
8119167Ssam 		return;
812*16694Smckusick 	dp = ndp->ni_pdir;
8139167Ssam 	oldparent = 0, doingdirectory = 0;
8149167Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
8159167Ssam 		register struct direct *d;
8169167Ssam 
817*16694Smckusick 		d = &ndp->ni_dent;
8189167Ssam 		/*
81911641Ssam 		 * Avoid ".", "..", and aliases of "." for obvious reasons.
8209167Ssam 		 */
82111641Ssam 		if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
82211641Ssam 		    (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
82311641Ssam 		    (dp == ip)) {
82411641Ssam 			iput(dp);
82511641Ssam 			if (dp == ip)
82611641Ssam 				irele(ip);
82711641Ssam 			else
82810051Ssam 				iput(ip);
82911641Ssam 			u.u_error = EINVAL;
83011641Ssam 			return;
8319167Ssam 		}
8329167Ssam 		oldparent = dp->i_number;
8339167Ssam 		doingdirectory++;
8349167Ssam 	}
83511641Ssam 	iput(dp);
8369167Ssam 
8379167Ssam 	/*
8389167Ssam 	 * 1) Bump link count while we're moving stuff
8399167Ssam 	 *    around.  If we crash somewhere before
8409167Ssam 	 *    completing our work, the link count
8419167Ssam 	 *    may be wrong, but correctable.
8429167Ssam 	 */
8439167Ssam 	ip->i_nlink++;
8449167Ssam 	ip->i_flag |= ICHG;
8459167Ssam 	iupdat(ip, &time, &time, 1);
84616664Smckusick 	IUNLOCK(ip);
8479167Ssam 
8489167Ssam 	/*
8499167Ssam 	 * When the target exists, both the directory
8509167Ssam 	 * and target inodes are returned locked.
8519167Ssam 	 */
852*16694Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE;
853*16694Smckusick 	ndp->ni_dirp = (caddr_t)uap->to;
854*16694Smckusick 	xp = namei(ndp);
85510051Ssam 	if (u.u_error) {
85610051Ssam 		error = u.u_error;
8579167Ssam 		goto out;
85810051Ssam 	}
859*16694Smckusick 	dp = ndp->ni_pdir;
8609167Ssam 	/*
86111641Ssam 	 * If ".." must be changed (ie the directory gets a new
86212816Smckusick 	 * parent) then the source directory must not be in the
86312816Smckusick 	 * directory heirarchy above the target, as this would
86412816Smckusick 	 * orphan everything below the source directory. Also
86512816Smckusick 	 * the user must have write permission in the source so
86612816Smckusick 	 * as to be able to change "..". We must repeat the call
86712816Smckusick 	 * to namei, as the parent directory is unlocked by the
86812816Smckusick 	 * call to checkpath().
86911641Ssam 	 */
87011641Ssam 	parentdifferent = oldparent != dp->i_number;
87112816Smckusick 	if (doingdirectory && parentdifferent) {
87212816Smckusick 		if (access(ip, IWRITE))
87312816Smckusick 			goto bad;
87412816Smckusick 		do {
875*16694Smckusick 			dp = ndp->ni_pdir;
87612816Smckusick 			if (xp != NULL)
87712816Smckusick 				iput(xp);
87812816Smckusick 			u.u_error = checkpath(ip, dp);
87912816Smckusick 			if (u.u_error)
88012816Smckusick 				goto out;
881*16694Smckusick 			xp = namei(ndp);
88212816Smckusick 			if (u.u_error) {
88312816Smckusick 				error = u.u_error;
88412816Smckusick 				goto out;
88512816Smckusick 			}
886*16694Smckusick 		} while (dp != ndp->ni_pdir);
88712816Smckusick 	}
88811641Ssam 	/*
8899167Ssam 	 * 2) If target doesn't exist, link the target
8909167Ssam 	 *    to the source and unlink the source.
8919167Ssam 	 *    Otherwise, rewrite the target directory
8929167Ssam 	 *    entry to reference the source inode and
8939167Ssam 	 *    expunge the original entry's existence.
8949167Ssam 	 */
8959167Ssam 	if (xp == NULL) {
8969167Ssam 		if (dp->i_dev != ip->i_dev) {
89710051Ssam 			error = EXDEV;
8989167Ssam 			goto bad;
8999167Ssam 		}
9009167Ssam 		/*
9019167Ssam 		 * Account for ".." in directory.
9029167Ssam 		 * When source and destination have the
9039167Ssam 		 * same parent we don't fool with the
9049167Ssam 		 * link count -- this isn't required
9059167Ssam 		 * because we do a similar check below.
9069167Ssam 		 */
9079167Ssam 		if (doingdirectory && parentdifferent) {
9089167Ssam 			dp->i_nlink++;
9099167Ssam 			dp->i_flag |= ICHG;
9109167Ssam 			iupdat(dp, &time, &time, 1);
9119167Ssam 		}
912*16694Smckusick 		error = direnter(ip, ndp);
91310850Ssam 		if (error)
9149167Ssam 			goto out;
9159167Ssam 	} else {
9169167Ssam 		if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
91710051Ssam 			error = EXDEV;
9189167Ssam 			goto bad;
9199167Ssam 		}
9209167Ssam 		/*
92110590Ssam 		 * Short circuit rename(foo, foo).
92210590Ssam 		 */
92310590Ssam 		if (xp->i_number == ip->i_number)
92410590Ssam 			goto bad;
92510590Ssam 		/*
92610051Ssam 		 * Target must be empty if a directory
92710051Ssam 		 * and have no links to it.
9289167Ssam 		 * Also, insure source and target are
9299167Ssam 		 * compatible (both directories, or both
9309167Ssam 		 * not directories).
9319167Ssam 		 */
9329167Ssam 		if ((xp->i_mode&IFMT) == IFDIR) {
93310051Ssam 			if (!dirempty(xp) || xp->i_nlink > 2) {
93410051Ssam 				error = ENOTEMPTY;
9359167Ssam 				goto bad;
9369167Ssam 			}
9379167Ssam 			if (!doingdirectory) {
93810051Ssam 				error = ENOTDIR;
9399167Ssam 				goto bad;
9409167Ssam 			}
9419167Ssam 		} else if (doingdirectory) {
94210051Ssam 			error = EISDIR;
9439167Ssam 			goto bad;
9449167Ssam 		}
945*16694Smckusick 		dirrewrite(dp, ip, ndp);
94610051Ssam 		if (u.u_error) {
94710051Ssam 			error = u.u_error;
9489167Ssam 			goto bad1;
94910051Ssam 		}
9509167Ssam 		/*
95110051Ssam 		 * Adjust the link count of the target to
95210051Ssam 		 * reflect the dirrewrite above.  If this is
95310051Ssam 		 * a directory it is empty and there are
95410051Ssam 		 * no links to it, so we can squash the inode and
95510051Ssam 		 * any space associated with it.  We disallowed
95610051Ssam 		 * renaming over top of a directory with links to
95710051Ssam 		 * it above, as we've no way to determine if
95810051Ssam 		 * we've got a link or the directory itself, and
95910051Ssam 		 * if we get a link, then ".." will be screwed up.
9609167Ssam 		 */
96110051Ssam 		xp->i_nlink--;
9629167Ssam 		if (doingdirectory) {
96310051Ssam 			if (--xp->i_nlink != 0)
96410051Ssam 				panic("rename: linked directory");
9659167Ssam 			itrunc(xp, (u_long)0);
96610051Ssam 		}
9679167Ssam 		xp->i_flag |= ICHG;
9689167Ssam 		iput(xp);
96910246Ssam 		xp = NULL;
9709167Ssam 	}
9719167Ssam 
9729167Ssam 	/*
9739167Ssam 	 * 3) Unlink the source.
9749167Ssam 	 */
975*16694Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT;
976*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
977*16694Smckusick 	ndp->ni_dirp = uap->from;
978*16694Smckusick 	zp = namei(ndp);
979*16694Smckusick 	dp = ndp->ni_pdir;
9809167Ssam 	/*
9819167Ssam 	 * Insure directory entry still exists and
9829167Ssam 	 * has not changed since the start of all
9839167Ssam 	 * this.  If either has occured, forget about
98416652Ssam 	 * about deleting the original entry.
9859167Ssam 	 */
98616655Smckusick 	if (dp != NULL && zp == ip) {
9879167Ssam 		/*
9889167Ssam 		 * If source is a directory, must adjust
9899167Ssam 		 * link count of parent directory also.
9909167Ssam 		 * If target didn't exist and source and
9919167Ssam 		 * target have the same parent, then we
9929167Ssam 		 * needn't touch the link count, it all
9939167Ssam 		 * balances out in the end.  Otherwise, we
9949167Ssam 		 * must do so to reflect deletion of ".."
9959167Ssam 		 * done above.
9969167Ssam 		 */
9979167Ssam 		if (doingdirectory && (xp != NULL || parentdifferent)) {
9989167Ssam 			dp->i_nlink--;
9999167Ssam 			dp->i_flag |= ICHG;
10009167Ssam 		}
1001*16694Smckusick 		if (dirremove(ndp)) {
100216655Smckusick 			zp->i_nlink--;
100316655Smckusick 			zp->i_flag |= ICHG;
10049167Ssam 		}
100510051Ssam 		if (error == 0)		/* conservative */
100610051Ssam 			error = u.u_error;
10079167Ssam 	}
100816655Smckusick 	if (zp != NULL)
100916655Smckusick 		iput(zp);
10109167Ssam 	irele(ip);
10119167Ssam 	if (dp)
10129167Ssam 		iput(dp);
10139167Ssam 
10149167Ssam 	/*
10159167Ssam 	 * 4) Renaming a directory with the parent
10169167Ssam 	 *    different requires ".." to be rewritten.
10179167Ssam 	 *    The window is still there for ".." to
10189167Ssam 	 *    be inconsistent, but this is unavoidable,
10199167Ssam 	 *    and a lot shorter than when it was done
10209167Ssam 	 *    in a user process.
10219167Ssam 	 */
102210051Ssam 	if (doingdirectory && parentdifferent && error == 0) {
10239167Ssam 		struct dirtemplate dirbuf;
10249167Ssam 
1025*16694Smckusick 		ndp->ni_nameiop = LOOKUP | LOCKPARENT;
1026*16694Smckusick 		ndp->ni_segflg = UIO_USERSPACE;
1027*16694Smckusick 		ndp->ni_dirp = uap->to;
1028*16694Smckusick 		ip = namei(ndp);
10299167Ssam 		if (ip == NULL) {
10309167Ssam 			printf("rename: .. went away\n");
10319167Ssam 			return;
10329167Ssam 		}
1033*16694Smckusick 		dp = ndp->ni_pdir;
10349167Ssam 		if ((ip->i_mode&IFMT) != IFDIR) {
10359167Ssam 			printf("rename: .. not a directory\n");
10369167Ssam 			goto stuck;
10379167Ssam 		}
103810051Ssam 		error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
10399167Ssam 			sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
104010051Ssam 		if (error == 0) {
10419167Ssam 			dirbuf.dotdot_ino = dp->i_number;
104216644Ssam 			dp->i_id = ++nextinodeid;
10439167Ssam 			(void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf,
10449167Ssam 			  sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
10459167Ssam 		}
10469167Ssam stuck:
10479167Ssam 		irele(dp);
10489167Ssam 		iput(ip);
10499167Ssam 	}
105010051Ssam 	goto done;
105110051Ssam 
10529167Ssam bad:
105310246Ssam 	iput(dp);
10549167Ssam bad1:
10559167Ssam 	if (xp)
105610246Ssam 		iput(xp);
10579167Ssam out:
10589167Ssam 	ip->i_nlink--;
10599167Ssam 	ip->i_flag |= ICHG;
10609167Ssam 	irele(ip);
106110051Ssam done:
106210051Ssam 	if (error)
106310051Ssam 		u.u_error = error;
10647701Ssam }
10657701Ssam 
10667535Sroot /*
10677535Sroot  * Make a new file.
10687535Sroot  */
10697535Sroot struct inode *
1070*16694Smckusick maknode(mode, ndp)
10717535Sroot 	int mode;
1072*16694Smckusick 	register struct nameidata *ndp;
10737535Sroot {
10747535Sroot 	register struct inode *ip;
1075*16694Smckusick 	register struct inode *pdir = ndp->ni_pdir;
10767535Sroot 	ino_t ipref;
10777535Sroot 
10787535Sroot 	if ((mode & IFMT) == IFDIR)
1079*16694Smckusick 		ipref = dirpref(pdir->i_fs);
10807535Sroot 	else
1081*16694Smckusick 		ipref = pdir->i_number;
1082*16694Smckusick 	ip = ialloc(pdir, ipref, mode);
10837535Sroot 	if (ip == NULL) {
1084*16694Smckusick 		iput(pdir);
10857701Ssam 		return (NULL);
10867535Sroot 	}
10877701Ssam #ifdef QUOTA
10887535Sroot 	if (ip->i_dquot != NODQUOT)
10897535Sroot 		panic("maknode: dquot");
10907535Sroot #endif
10917535Sroot 	ip->i_flag |= IACC|IUPD|ICHG;
10927535Sroot 	if ((mode & IFMT) == 0)
10937535Sroot 		mode |= IFREG;
10947535Sroot 	ip->i_mode = mode & ~u.u_cmask;
10957535Sroot 	ip->i_nlink = 1;
10967535Sroot 	ip->i_uid = u.u_uid;
1097*16694Smckusick 	ip->i_gid = pdir->i_gid;
109811811Ssam 	if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
109911811Ssam 		ip->i_mode &= ~ISGID;
11007701Ssam #ifdef QUOTA
11017535Sroot 	ip->i_dquot = inoquota(ip);
11027535Sroot #endif
11037535Sroot 
11047535Sroot 	/*
11057535Sroot 	 * Make sure inode goes to disk before directory entry.
11067535Sroot 	 */
11078673Sroot 	iupdat(ip, &time, &time, 1);
1108*16694Smckusick 	u.u_error = direnter(ip, ndp);
11097535Sroot 	if (u.u_error) {
11107535Sroot 		/*
111110850Ssam 		 * Write error occurred trying to update directory
111210850Ssam 		 * so must deallocate the inode.
11137535Sroot 		 */
11147535Sroot 		ip->i_nlink = 0;
11157535Sroot 		ip->i_flag |= ICHG;
11167535Sroot 		iput(ip);
11177701Ssam 		return (NULL);
11187535Sroot 	}
11197701Ssam 	return (ip);
11207535Sroot }
112112756Ssam 
112212756Ssam /*
112312756Ssam  * A virgin directory (no blushing please).
112412756Ssam  */
112512756Ssam struct dirtemplate mastertemplate = {
112612756Ssam 	0, 12, 1, ".",
112712756Ssam 	0, DIRBLKSIZ - 12, 2, ".."
112812756Ssam };
112912756Ssam 
113012756Ssam /*
113112756Ssam  * Mkdir system call
113212756Ssam  */
113312756Ssam mkdir()
113412756Ssam {
113512756Ssam 	struct a {
113612756Ssam 		char	*name;
113712756Ssam 		int	dmode;
1138*16694Smckusick 	} *uap = (struct a *)u.u_ap;
113912756Ssam 	register struct inode *ip, *dp;
114012756Ssam 	struct dirtemplate dirtemplate;
1141*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
114212756Ssam 
1143*16694Smckusick 	ndp->ni_nameiop = CREATE;
1144*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
1145*16694Smckusick 	ndp->ni_dirp = uap->name;
1146*16694Smckusick 	ip = namei(ndp);
114712756Ssam 	if (u.u_error)
114812756Ssam 		return;
114912756Ssam 	if (ip != NULL) {
115012756Ssam 		iput(ip);
115112756Ssam 		u.u_error = EEXIST;
115212756Ssam 		return;
115312756Ssam 	}
1154*16694Smckusick 	dp = ndp->ni_pdir;
115512756Ssam 	uap->dmode &= 0777;
115612756Ssam 	uap->dmode |= IFDIR;
115712756Ssam 	/*
115812756Ssam 	 * Must simulate part of maknode here
115912756Ssam 	 * in order to acquire the inode, but
116012756Ssam 	 * not have it entered in the parent
116112756Ssam 	 * directory.  The entry is made later
116212756Ssam 	 * after writing "." and ".." entries out.
116312756Ssam 	 */
116412756Ssam 	ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
116512756Ssam 	if (ip == NULL) {
116612756Ssam 		iput(dp);
116712756Ssam 		return;
116812756Ssam 	}
116912756Ssam #ifdef QUOTA
117012756Ssam 	if (ip->i_dquot != NODQUOT)
117112756Ssam 		panic("mkdir: dquot");
117212756Ssam #endif
117312756Ssam 	ip->i_flag |= IACC|IUPD|ICHG;
117412756Ssam 	ip->i_mode = uap->dmode & ~u.u_cmask;
117512756Ssam 	ip->i_nlink = 2;
117612756Ssam 	ip->i_uid = u.u_uid;
117712756Ssam 	ip->i_gid = dp->i_gid;
117812756Ssam #ifdef QUOTA
117912756Ssam 	ip->i_dquot = inoquota(ip);
118012756Ssam #endif
118112756Ssam 	iupdat(ip, &time, &time, 1);
118212756Ssam 
118312756Ssam 	/*
118412756Ssam 	 * Bump link count in parent directory
118512756Ssam 	 * to reflect work done below.  Should
118612756Ssam 	 * be done before reference is created
118712756Ssam 	 * so reparation is possible if we crash.
118812756Ssam 	 */
118912756Ssam 	dp->i_nlink++;
119012756Ssam 	dp->i_flag |= ICHG;
119112756Ssam 	iupdat(dp, &time, &time, 1);
119212756Ssam 
119312756Ssam 	/*
119412756Ssam 	 * Initialize directory with "."
119512756Ssam 	 * and ".." from static template.
119612756Ssam 	 */
119712756Ssam 	dirtemplate = mastertemplate;
119812756Ssam 	dirtemplate.dot_ino = ip->i_number;
119912756Ssam 	dirtemplate.dotdot_ino = dp->i_number;
120012756Ssam 	u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
120112756Ssam 		sizeof (dirtemplate), (off_t)0, 1, (int *)0);
120212756Ssam 	if (u.u_error) {
120312756Ssam 		dp->i_nlink--;
120412756Ssam 		dp->i_flag |= ICHG;
120512756Ssam 		goto bad;
120612756Ssam 	}
120712756Ssam 	/*
120812756Ssam 	 * Directory all set up, now
120912756Ssam 	 * install the entry for it in
121012756Ssam 	 * the parent directory.
121112756Ssam 	 */
1212*16694Smckusick 	u.u_error = direnter(ip, ndp);
121312756Ssam 	dp = NULL;
121412756Ssam 	if (u.u_error) {
1215*16694Smckusick 		ndp->ni_nameiop = LOOKUP | NOCACHE;
1216*16694Smckusick 		ndp->ni_segflg = UIO_USERSPACE;
1217*16694Smckusick 		ndp->ni_dirp = uap->name;
1218*16694Smckusick 		dp = namei(ndp);
121912756Ssam 		if (dp) {
122012756Ssam 			dp->i_nlink--;
122112756Ssam 			dp->i_flag |= ICHG;
122212756Ssam 		}
122312756Ssam 	}
122412756Ssam bad:
122512756Ssam 	/*
122612756Ssam 	 * No need to do an explicit itrunc here,
122712756Ssam 	 * irele will do this for us because we set
122812756Ssam 	 * the link count to 0.
122912756Ssam 	 */
123012756Ssam 	if (u.u_error) {
123112756Ssam 		ip->i_nlink = 0;
123212756Ssam 		ip->i_flag |= ICHG;
123312756Ssam 	}
123412756Ssam 	if (dp)
123512756Ssam 		iput(dp);
123612756Ssam 	iput(ip);
123712756Ssam }
123812756Ssam 
123912756Ssam /*
124012756Ssam  * Rmdir system call.
124112756Ssam  */
124212756Ssam rmdir()
124312756Ssam {
124412756Ssam 	struct a {
124512756Ssam 		char	*name;
1246*16694Smckusick 	} *uap = (struct a *)u.u_ap;
124712756Ssam 	register struct inode *ip, *dp;
1248*16694Smckusick 	register struct nameidata *ndp = &u.u_nd;
124912756Ssam 
1250*16694Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT;
1251*16694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
1252*16694Smckusick 	ndp->ni_dirp = uap->name;
1253*16694Smckusick 	ip = namei(ndp);
125412756Ssam 	if (ip == NULL)
125512756Ssam 		return;
1256*16694Smckusick 	dp = ndp->ni_pdir;
125712756Ssam 	/*
125812756Ssam 	 * No rmdir "." please.
125912756Ssam 	 */
126012756Ssam 	if (dp == ip) {
126112756Ssam 		irele(dp);
126212756Ssam 		iput(ip);
126312756Ssam 		u.u_error = EINVAL;
126412756Ssam 		return;
126512756Ssam 	}
126612756Ssam 	if ((ip->i_mode&IFMT) != IFDIR) {
126712756Ssam 		u.u_error = ENOTDIR;
126812756Ssam 		goto out;
126912756Ssam 	}
127012756Ssam 	/*
127112756Ssam 	 * Don't remove a mounted on directory.
127212756Ssam 	 */
127312756Ssam 	if (ip->i_dev != dp->i_dev) {
127412756Ssam 		u.u_error = EBUSY;
127512756Ssam 		goto out;
127612756Ssam 	}
127712756Ssam 	/*
127812756Ssam 	 * Verify the directory is empty (and valid).
127912756Ssam 	 * (Rmdir ".." won't be valid since
128012756Ssam 	 *  ".." will contain a reference to
128112756Ssam 	 *  the current directory and thus be
128212756Ssam 	 *  non-empty.)
128312756Ssam 	 */
128412756Ssam 	if (ip->i_nlink != 2 || !dirempty(ip)) {
128512756Ssam 		u.u_error = ENOTEMPTY;
128612756Ssam 		goto out;
128712756Ssam 	}
128812756Ssam 	/*
128912756Ssam 	 * Delete reference to directory before purging
129012756Ssam 	 * inode.  If we crash in between, the directory
129112756Ssam 	 * will be reattached to lost+found,
129212756Ssam 	 */
1293*16694Smckusick 	if (dirremove(ndp) == 0)
129412756Ssam 		goto out;
129512756Ssam 	dp->i_nlink--;
129612756Ssam 	dp->i_flag |= ICHG;
129712756Ssam 	iput(dp);
129812756Ssam 	dp = NULL;
129912756Ssam 	/*
130012756Ssam 	 * Truncate inode.  The only stuff left
130112756Ssam 	 * in the directory is "." and "..".  The
130212756Ssam 	 * "." reference is inconsequential since
130312756Ssam 	 * we're quashing it.  The ".." reference
130412756Ssam 	 * has already been adjusted above.  We've
130512756Ssam 	 * removed the "." reference and the reference
130612756Ssam 	 * in the parent directory, but there may be
130712756Ssam 	 * other hard links so decrement by 2 and
130812756Ssam 	 * worry about them later.
130912756Ssam 	 */
131012756Ssam 	ip->i_nlink -= 2;
131112756Ssam 	itrunc(ip, (u_long)0);
131212756Ssam out:
131312756Ssam 	if (dp)
131412756Ssam 		iput(dp);
131512756Ssam 	iput(ip);
131612756Ssam }
131712756Ssam 
131812756Ssam struct file *
131912756Ssam getinode(fdes)
132012756Ssam 	int fdes;
132112756Ssam {
132216540Ssam 	struct file *fp;
132312756Ssam 
132416540Ssam 	if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
132516540Ssam 		u.u_error = EBADF;
132616540Ssam 		return ((struct file *)0);
132716540Ssam 	}
132812756Ssam 	if (fp->f_type != DTYPE_INODE) {
132912756Ssam 		u.u_error = EINVAL;
133016540Ssam 		return ((struct file *)0);
133112756Ssam 	}
133212756Ssam 	return (fp);
133312756Ssam }
133412756Ssam 
133512756Ssam /*
133612756Ssam  * mode mask for creation of files
133712756Ssam  */
133812756Ssam umask()
133912756Ssam {
134012756Ssam 	register struct a {
134112756Ssam 		int	mask;
1342*16694Smckusick 	} *uap = (struct a *)u.u_ap;
134312756Ssam 
134412756Ssam 	u.u_r.r_val1 = u.u_cmask;
134512756Ssam 	u.u_cmask = uap->mask & 07777;
134612756Ssam }
1347