xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 16655)
1*16655Smckusick /*	vfs_syscalls.c	6.9	84/07/02	*/
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"
189167Ssam #include "../h/nami.h"
1912756Ssam #include "../h/mount.h"
2037Sbill 
2112756Ssam extern	struct fileops inodeops;
2212756Ssam struct	file *getinode();
2312756Ssam 
249167Ssam /*
259167Ssam  * Change current working directory (``.'').
269167Ssam  */
276254Sroot chdir()
286254Sroot {
296254Sroot 
306254Sroot 	chdirec(&u.u_cdir);
316254Sroot }
326254Sroot 
339167Ssam /*
349167Ssam  * Change notion of root (``/'') directory.
359167Ssam  */
366254Sroot chroot()
376254Sroot {
386254Sroot 
396254Sroot 	if (suser())
406254Sroot 		chdirec(&u.u_rdir);
416254Sroot }
426254Sroot 
439167Ssam /*
449167Ssam  * Common routine for chroot and chdir.
459167Ssam  */
466254Sroot chdirec(ipp)
477701Ssam 	register struct inode **ipp;
486254Sroot {
496254Sroot 	register struct inode *ip;
506254Sroot 	struct a {
516254Sroot 		char	*fname;
526254Sroot 	};
536254Sroot 
549167Ssam 	ip = namei(uchar, LOOKUP, 1);
559167Ssam 	if (ip == NULL)
566254Sroot 		return;
579167Ssam 	if ((ip->i_mode&IFMT) != IFDIR) {
586254Sroot 		u.u_error = ENOTDIR;
596254Sroot 		goto bad;
606254Sroot 	}
619167Ssam 	if (access(ip, IEXEC))
626254Sroot 		goto bad;
637122Smckusick 	iunlock(ip);
647142Smckusick 	if (*ipp)
657142Smckusick 		irele(*ipp);
666254Sroot 	*ipp = ip;
676254Sroot 	return;
686254Sroot 
696254Sroot bad:
706254Sroot 	iput(ip);
716254Sroot }
726254Sroot 
7337Sbill /*
746254Sroot  * Open system call.
756254Sroot  */
766254Sroot open()
776254Sroot {
7812756Ssam 	struct a {
796254Sroot 		char	*fname;
807701Ssam 		int	mode;
8112756Ssam 		int	crtmode;
8212756Ssam 	} *uap = (struct a *) u.u_ap;
836254Sroot 
8412756Ssam 	copen(uap->mode-FOPEN, uap->crtmode);
856254Sroot }
866254Sroot 
876254Sroot /*
886254Sroot  * Creat system call.
896254Sroot  */
9012756Ssam creat()
916254Sroot {
9212756Ssam 	struct a {
936254Sroot 		char	*fname;
946254Sroot 		int	fmode;
9512756Ssam 	} *uap = (struct a *)u.u_ap;
966254Sroot 
9712756Ssam 	copen(FWRITE|FCREAT|FTRUNC, uap->fmode);
986254Sroot }
996254Sroot 
1006254Sroot /*
1016254Sroot  * Common code for open and creat.
10212756Ssam  * Check permissions, allocate an open file structure,
10312756Ssam  * and call the device open routine if any.
1046254Sroot  */
10512756Ssam copen(mode, arg)
10612756Ssam 	register int mode;
10712756Ssam 	int arg;
10812756Ssam {
1096254Sroot 	register struct inode *ip;
1106254Sroot 	register struct file *fp;
11112756Ssam 	int i;
1126254Sroot 
11312756Ssam #ifdef notdef
11412756Ssam 	if ((mode&(FREAD|FWRITE)) == 0) {
11512756Ssam 		u.u_error = EINVAL;
11612756Ssam 		return;
11712756Ssam 	}
11812756Ssam #endif
11912756Ssam 	if (mode&FCREAT) {
12012756Ssam 		ip = namei(uchar, CREATE, 1);
12112756Ssam 		if (ip == NULL) {
12212756Ssam 			if (u.u_error)
12312756Ssam 				return;
12412756Ssam 			ip = maknode(arg&07777&(~ISVTX));
12512756Ssam 			if (ip == NULL)
12612756Ssam 				return;
12712756Ssam 			mode &= ~FTRUNC;
12812756Ssam 		} else {
12912756Ssam 			if (mode&FEXCL) {
13012756Ssam 				u.u_error = EEXIST;
13112756Ssam 				iput(ip);
13212756Ssam 				return;
13312756Ssam 			}
13412756Ssam 			mode &= ~FCREAT;
13512756Ssam 		}
13612756Ssam 	} else {
13712756Ssam 		ip = namei(uchar, LOOKUP, 1);
13812756Ssam 		if (ip == NULL)
13912756Ssam 			return;
14012756Ssam 	}
14112756Ssam 	if ((ip->i_mode & IFMT) == IFSOCK) {
14212756Ssam 		u.u_error = EOPNOTSUPP;
14312756Ssam 		goto bad;
14412756Ssam 	}
14512756Ssam 	if ((mode&FCREAT) == 0) {
1466254Sroot 		if (mode&FREAD)
1477701Ssam 			if (access(ip, IREAD))
1487701Ssam 				goto bad;
14916032Skarels 		if (mode&(FWRITE|FTRUNC)) {
1507701Ssam 			if (access(ip, IWRITE))
1517701Ssam 				goto bad;
1527701Ssam 			if ((ip->i_mode&IFMT) == IFDIR) {
1536254Sroot 				u.u_error = EISDIR;
1547701Ssam 				goto bad;
1557701Ssam 			}
1566254Sroot 		}
1576254Sroot 	}
15812756Ssam 	fp = falloc();
15912756Ssam 	if (fp == NULL)
16012756Ssam 		goto bad;
16112756Ssam 	if (mode&FTRUNC)
1629167Ssam 		itrunc(ip, (u_long)0);
1637122Smckusick 	iunlock(ip);
16412756Ssam 	fp->f_flag = mode&FMASK;
16512756Ssam 	fp->f_type = DTYPE_INODE;
16612756Ssam 	fp->f_ops = &inodeops;
16712756Ssam 	fp->f_data = (caddr_t)ip;
1686254Sroot 	i = u.u_r.r_val1;
16912756Ssam 	if (setjmp(&u.u_qsave)) {
17012756Ssam 		if (u.u_error == 0)
17112756Ssam 			u.u_error = EINTR;
17212756Ssam 		u.u_ofile[i] = NULL;
17312756Ssam 		closef(fp);
17412756Ssam 		return;
17512756Ssam 	}
1768559Sroot 	u.u_error = openi(ip, mode);
17712756Ssam 	if (u.u_error == 0)
1786254Sroot 		return;
1796254Sroot 	u.u_ofile[i] = NULL;
1806254Sroot 	fp->f_count--;
1817142Smckusick 	irele(ip);
1827701Ssam 	return;
1837701Ssam bad:
1847701Ssam 	iput(ip);
1856254Sroot }
1866254Sroot 
1876254Sroot /*
1886254Sroot  * Mknod system call
1896254Sroot  */
1906254Sroot mknod()
1916254Sroot {
1926254Sroot 	register struct inode *ip;
1936254Sroot 	register struct a {
1946254Sroot 		char	*fname;
1956254Sroot 		int	fmode;
1966254Sroot 		int	dev;
1976254Sroot 	} *uap;
1986254Sroot 
1996254Sroot 	uap = (struct a *)u.u_ap;
20012756Ssam 	if (!suser())
20112756Ssam 		return;
20212756Ssam 	ip = namei(uchar, CREATE, 0);
20312756Ssam 	if (ip != NULL) {
20412756Ssam 		u.u_error = EEXIST;
20512756Ssam 		goto out;
2066254Sroot 	}
2076254Sroot 	if (u.u_error)
2086254Sroot 		return;
2096254Sroot 	ip = maknode(uap->fmode);
2106254Sroot 	if (ip == NULL)
2116254Sroot 		return;
21212756Ssam 	switch (ip->i_mode & IFMT) {
21312756Ssam 
21415093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
21512756Ssam 	case IFCHR:
21612756Ssam 	case IFBLK:
21712756Ssam 		if (uap->dev) {
21812756Ssam 			/*
21912756Ssam 			 * Want to be able to use this to make badblock
22012756Ssam 			 * inodes, so don't truncate the dev number.
22112756Ssam 			 */
22212756Ssam 			ip->i_rdev = uap->dev;
22312756Ssam 			ip->i_flag |= IACC|IUPD|ICHG;
22412756Ssam 		}
2256254Sroot 	}
2266254Sroot 
2276254Sroot out:
2286254Sroot 	iput(ip);
2296254Sroot }
2306254Sroot 
2316254Sroot /*
2326254Sroot  * link system call
2336254Sroot  */
2346254Sroot link()
2356254Sroot {
2366254Sroot 	register struct inode *ip, *xp;
2376254Sroot 	register struct a {
2386254Sroot 		char	*target;
2396254Sroot 		char	*linkname;
2406254Sroot 	} *uap;
2416254Sroot 
2426254Sroot 	uap = (struct a *)u.u_ap;
2439167Ssam 	ip = namei(uchar, LOOKUP, 1); /* well, this routine is doomed anyhow */
2446254Sroot 	if (ip == NULL)
2456254Sroot 		return;
2469167Ssam 	if ((ip->i_mode&IFMT) == IFDIR && !suser()) {
2477439Sroot 		iput(ip);
2487439Sroot 		return;
2497439Sroot 	}
2506254Sroot 	ip->i_nlink++;
2516254Sroot 	ip->i_flag |= ICHG;
2528673Sroot 	iupdat(ip, &time, &time, 1);
2537122Smckusick 	iunlock(ip);
2546254Sroot 	u.u_dirp = (caddr_t)uap->linkname;
2559167Ssam 	xp = namei(uchar, CREATE, 0);
2566254Sroot 	if (xp != NULL) {
2576254Sroot 		u.u_error = EEXIST;
2586254Sroot 		iput(xp);
2596254Sroot 		goto out;
2606254Sroot 	}
2616254Sroot 	if (u.u_error)
2626254Sroot 		goto out;
2636254Sroot 	if (u.u_pdir->i_dev != ip->i_dev) {
2646254Sroot 		iput(u.u_pdir);
2656254Sroot 		u.u_error = EXDEV;
2666254Sroot 		goto out;
2676254Sroot 	}
26810850Ssam 	u.u_error = direnter(ip);
2696254Sroot out:
2706254Sroot 	if (u.u_error) {
2716254Sroot 		ip->i_nlink--;
2726254Sroot 		ip->i_flag |= ICHG;
2736254Sroot 	}
2747142Smckusick 	irele(ip);
2756254Sroot }
2766254Sroot 
2776254Sroot /*
2786254Sroot  * symlink -- make a symbolic link
2796254Sroot  */
2806254Sroot symlink()
2816254Sroot {
2826254Sroot 	register struct a {
2836254Sroot 		char	*target;
2846254Sroot 		char	*linkname;
2856254Sroot 	} *uap;
2866254Sroot 	register struct inode *ip;
2876254Sroot 	register char *tp;
2886254Sroot 	register c, nc;
2896254Sroot 
2906254Sroot 	uap = (struct a *)u.u_ap;
2916254Sroot 	tp = uap->target;
2926254Sroot 	nc = 0;
2936254Sroot 	while (c = fubyte(tp)) {
2946254Sroot 		if (c < 0) {
2956254Sroot 			u.u_error = EFAULT;
2966254Sroot 			return;
2976254Sroot 		}
2986254Sroot 		tp++;
2996254Sroot 		nc++;
3006254Sroot 	}
3016254Sroot 	u.u_dirp = uap->linkname;
3029167Ssam 	ip = namei(uchar, CREATE, 0);
3036254Sroot 	if (ip) {
3046254Sroot 		iput(ip);
3056254Sroot 		u.u_error = EEXIST;
3066254Sroot 		return;
3076254Sroot 	}
3086254Sroot 	if (u.u_error)
3096254Sroot 		return;
3106254Sroot 	ip = maknode(IFLNK | 0777);
3116254Sroot 	if (ip == NULL)
3126254Sroot 		return;
3137826Sroot 	u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0);
3149167Ssam 	/* handle u.u_error != 0 */
3156254Sroot 	iput(ip);
3166254Sroot }
3176254Sroot 
3186254Sroot /*
3196254Sroot  * Unlink system call.
3206254Sroot  * Hard to avoid races here, especially
3216254Sroot  * in unlinking directories.
3226254Sroot  */
3236254Sroot unlink()
3246254Sroot {
3256254Sroot 	struct a {
3266254Sroot 		char	*fname;
3276254Sroot 	};
3289167Ssam 	register struct inode *ip, *dp;
3296254Sroot 
3309167Ssam 	ip = namei(uchar, DELETE | LOCKPARENT, 0);
3319167Ssam 	if (ip == NULL)
3326254Sroot 		return;
3339167Ssam 	dp = u.u_pdir;
3349167Ssam 	if ((ip->i_mode&IFMT) == IFDIR && !suser())
3356254Sroot 		goto out;
3366254Sroot 	/*
3376254Sroot 	 * Don't unlink a mounted file.
3386254Sroot 	 */
3399167Ssam 	if (ip->i_dev != dp->i_dev) {
3406254Sroot 		u.u_error = EBUSY;
3416254Sroot 		goto out;
3426254Sroot 	}
3436254Sroot 	if (ip->i_flag&ITEXT)
3446254Sroot 		xrele(ip);	/* try once to free text */
3457535Sroot 	if (dirremove()) {
3467535Sroot 		ip->i_nlink--;
3477535Sroot 		ip->i_flag |= ICHG;
3486254Sroot 	}
3496254Sroot out:
3509167Ssam 	if (dp == ip)
3517142Smckusick 		irele(ip);
3527142Smckusick 	else
3537142Smckusick 		iput(ip);
3549167Ssam 	iput(dp);
3556254Sroot }
3566254Sroot 
3576254Sroot /*
3586254Sroot  * Seek system call
3596254Sroot  */
3608040Sroot lseek()
3616254Sroot {
3626254Sroot 	register struct file *fp;
3636254Sroot 	register struct a {
3647701Ssam 		int	fd;
3656254Sroot 		off_t	off;
3666254Sroot 		int	sbase;
3676254Sroot 	} *uap;
3686254Sroot 
3696254Sroot 	uap = (struct a *)u.u_ap;
37016540Ssam 	GETF(fp, uap->fd);
37116540Ssam 	if (fp->f_type != DTYPE_INODE) {
37216540Ssam 		u.u_error = ESPIPE;
3736254Sroot 		return;
37416540Ssam 	}
37513878Ssam 	switch (uap->sbase) {
37613878Ssam 
37713878Ssam 	case L_INCR:
37813878Ssam 		fp->f_offset += uap->off;
37913878Ssam 		break;
38013878Ssam 
38113878Ssam 	case L_XTND:
38213878Ssam 		fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
38313878Ssam 		break;
38413878Ssam 
38513878Ssam 	case L_SET:
38613878Ssam 		fp->f_offset = uap->off;
38713878Ssam 		break;
38813878Ssam 
38913878Ssam 	default:
39013878Ssam 		u.u_error = EINVAL;
39113878Ssam 		return;
39213878Ssam 	}
39313878Ssam 	u.u_r.r_off = fp->f_offset;
3946254Sroot }
3956254Sroot 
3966254Sroot /*
3976254Sroot  * Access system call
3986254Sroot  */
3996254Sroot saccess()
4006254Sroot {
4016254Sroot 	register svuid, svgid;
4026254Sroot 	register struct inode *ip;
4036254Sroot 	register struct a {
4046254Sroot 		char	*fname;
4056254Sroot 		int	fmode;
4066254Sroot 	} *uap;
4076254Sroot 
4086254Sroot 	uap = (struct a *)u.u_ap;
4096254Sroot 	svuid = u.u_uid;
4106254Sroot 	svgid = u.u_gid;
4116254Sroot 	u.u_uid = u.u_ruid;
4126254Sroot 	u.u_gid = u.u_rgid;
4139167Ssam 	ip = namei(uchar, LOOKUP, 1);
4146254Sroot 	if (ip != NULL) {
41512756Ssam 		if ((uap->fmode&R_OK) && access(ip, IREAD))
4167701Ssam 			goto done;
41712756Ssam 		if ((uap->fmode&W_OK) && access(ip, IWRITE))
4187701Ssam 			goto done;
41912756Ssam 		if ((uap->fmode&X_OK) && access(ip, IEXEC))
4207701Ssam 			goto done;
4217701Ssam done:
4226254Sroot 		iput(ip);
4236254Sroot 	}
4246254Sroot 	u.u_uid = svuid;
4256254Sroot 	u.u_gid = svgid;
4266254Sroot }
4276254Sroot 
4286254Sroot /*
4296574Smckusic  * Stat system call.  This version follows links.
43037Sbill  */
43137Sbill stat()
43237Sbill {
43337Sbill 
43412756Ssam 	stat1(1);
43537Sbill }
43637Sbill 
43737Sbill /*
4386574Smckusic  * Lstat system call.  This version does not follow links.
4395992Swnj  */
4405992Swnj lstat()
4415992Swnj {
44212756Ssam 
44312756Ssam 	stat1(0);
44412756Ssam }
44512756Ssam 
44612756Ssam stat1(follow)
44712756Ssam 	int follow;
44812756Ssam {
4495992Swnj 	register struct inode *ip;
4505992Swnj 	register struct a {
4515992Swnj 		char	*fname;
45212756Ssam 		struct stat *ub;
4535992Swnj 	} *uap;
45412756Ssam 	struct stat sb;
4555992Swnj 
4565992Swnj 	uap = (struct a *)u.u_ap;
45712756Ssam 	ip = namei(uchar, LOOKUP, follow);
4585992Swnj 	if (ip == NULL)
4595992Swnj 		return;
46013043Ssam 	(void) ino_stat(ip, &sb);
4615992Swnj 	iput(ip);
46212756Ssam 	u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
4635992Swnj }
4645992Swnj 
4655992Swnj /*
4665992Swnj  * Return target name of a symbolic link
46737Sbill  */
4685992Swnj readlink()
4695992Swnj {
4705992Swnj 	register struct inode *ip;
4715992Swnj 	register struct a {
4725992Swnj 		char	*name;
4735992Swnj 		char	*buf;
4745992Swnj 		int	count;
4757826Sroot 	} *uap = (struct a *)u.u_ap;
4767826Sroot 	int resid;
4775992Swnj 
4789167Ssam 	ip = namei(uchar, LOOKUP, 0);
4795992Swnj 	if (ip == NULL)
4805992Swnj 		return;
4815992Swnj 	if ((ip->i_mode&IFMT) != IFLNK) {
4825992Swnj 		u.u_error = ENXIO;
4835992Swnj 		goto out;
4845992Swnj 	}
4857826Sroot 	u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid);
4865992Swnj out:
4875992Swnj 	iput(ip);
4887826Sroot 	u.u_r.r_val1 = uap->count - resid;
4895992Swnj }
4905992Swnj 
4919167Ssam /*
4929167Ssam  * Change mode of a file given path name.
4939167Ssam  */
4946254Sroot chmod()
4955992Swnj {
4967701Ssam 	struct inode *ip;
4977701Ssam 	struct a {
4986254Sroot 		char	*fname;
4996254Sroot 		int	fmode;
5005992Swnj 	} *uap;
5015992Swnj 
5025992Swnj 	uap = (struct a *)u.u_ap;
5036254Sroot 	if ((ip = owner(1)) == NULL)
5045992Swnj 		return;
5057701Ssam 	chmod1(ip, uap->fmode);
5069167Ssam 	iput(ip);
5077701Ssam }
5087439Sroot 
5099167Ssam /*
5109167Ssam  * Change mode of a file given a file descriptor.
5119167Ssam  */
5127701Ssam fchmod()
5137701Ssam {
5147701Ssam 	struct a {
5157701Ssam 		int	fd;
5167701Ssam 		int	fmode;
5177701Ssam 	} *uap;
5187701Ssam 	register struct inode *ip;
5197701Ssam 	register struct file *fp;
5207701Ssam 
5217701Ssam 	uap = (struct a *)u.u_ap;
52212756Ssam 	fp = getinode(uap->fd);
5237701Ssam 	if (fp == NULL)
5247701Ssam 		return;
52512756Ssam 	ip = (struct inode *)fp->f_data;
5269167Ssam 	if (u.u_uid != ip->i_uid && !suser())
5279167Ssam 		return;
5287701Ssam 	ilock(ip);
5297701Ssam 	chmod1(ip, uap->fmode);
5309167Ssam 	iunlock(ip);
5317701Ssam }
5327701Ssam 
5339167Ssam /*
5349167Ssam  * Change the mode on a file.
5359167Ssam  * Inode must be locked before calling.
5369167Ssam  */
5377701Ssam chmod1(ip, mode)
5387701Ssam 	register struct inode *ip;
5397701Ssam 	register int mode;
5407701Ssam {
5417868Sroot 
5426254Sroot 	ip->i_mode &= ~07777;
5437439Sroot 	if (u.u_uid) {
5447701Ssam 		mode &= ~ISVTX;
54511811Ssam 		if (!groupmember(ip->i_gid))
54611811Ssam 			mode &= ~ISGID;
5477439Sroot 	}
5487701Ssam 	ip->i_mode |= mode&07777;
5496254Sroot 	ip->i_flag |= ICHG;
5506254Sroot 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
5516254Sroot 		xrele(ip);
5525992Swnj }
5535992Swnj 
5549167Ssam /*
5559167Ssam  * Set ownership given a path name.
5569167Ssam  */
5576254Sroot chown()
55837Sbill {
5597701Ssam 	struct inode *ip;
5607701Ssam 	struct a {
5616254Sroot 		char	*fname;
5626254Sroot 		int	uid;
5636254Sroot 		int	gid;
56437Sbill 	} *uap;
56537Sbill 
56637Sbill 	uap = (struct a *)u.u_ap;
56711821Ssam 	if (!suser() || (ip = owner(0)) == NULL)
56837Sbill 		return;
56911811Ssam 	u.u_error = chown1(ip, uap->uid, uap->gid);
5709167Ssam 	iput(ip);
5717701Ssam }
5727439Sroot 
5739167Ssam /*
5749167Ssam  * Set ownership given a file descriptor.
5759167Ssam  */
5767701Ssam fchown()
5777701Ssam {
5787701Ssam 	struct a {
5797701Ssam 		int	fd;
5807701Ssam 		int	uid;
5817701Ssam 		int	gid;
5827701Ssam 	} *uap;
5837701Ssam 	register struct inode *ip;
5847701Ssam 	register struct file *fp;
5857701Ssam 
5867701Ssam 	uap = (struct a *)u.u_ap;
58712756Ssam 	fp = getinode(uap->fd);
5887701Ssam 	if (fp == NULL)
5897701Ssam 		return;
59012756Ssam 	ip = (struct inode *)fp->f_data;
59111821Ssam 	if (!suser())
5929167Ssam 		return;
5937701Ssam 	ilock(ip);
59411811Ssam 	u.u_error = chown1(ip, uap->uid, uap->gid);
5959167Ssam 	iunlock(ip);
5967701Ssam }
5977701Ssam 
5987701Ssam /*
5997701Ssam  * Perform chown operation on inode ip;
6007701Ssam  * inode must be locked prior to call.
6017701Ssam  */
6027701Ssam chown1(ip, uid, gid)
6037701Ssam 	register struct inode *ip;
6047701Ssam 	int uid, gid;
6057701Ssam {
6067701Ssam #ifdef QUOTA
6077701Ssam 	register long change;
60811811Ssam #endif
6097701Ssam 
61011811Ssam 	if (uid == -1)
61111811Ssam 		uid = ip->i_uid;
61211811Ssam 	if (gid == -1)
61311811Ssam 		gid = ip->i_gid;
61411811Ssam #ifdef QUOTA
61514385Ssam 	if (ip->i_uid == uid)		/* this just speeds things a little */
6167482Skre 		change = 0;
61712646Ssam 	else
61812646Ssam 		change = ip->i_blocks;
61912646Ssam 	(void) chkdq(ip, -change, 1);
62012646Ssam 	(void) chkiq(ip->i_dev, ip, ip->i_uid, 1);
6217482Skre 	dqrele(ip->i_dquot);
6227482Skre #endif
62311811Ssam 	ip->i_uid = uid;
62411811Ssam 	ip->i_gid = gid;
6256254Sroot 	ip->i_flag |= ICHG;
6266254Sroot 	if (u.u_ruid != 0)
6276254Sroot 		ip->i_mode &= ~(ISUID|ISGID);
6287701Ssam #ifdef QUOTA
6297482Skre 	ip->i_dquot = inoquota(ip);
63012646Ssam 	(void) chkdq(ip, change, 1);
63112646Ssam 	(void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
63212646Ssam 	return (u.u_error);		/* should == 0 ALWAYS !! */
63312646Ssam #else
63412646Ssam 	return (0);
6357482Skre #endif
63637Sbill }
63737Sbill 
63811811Ssam utimes()
63911811Ssam {
64011811Ssam 	register struct a {
64111811Ssam 		char	*fname;
64211811Ssam 		struct	timeval *tptr;
64311811Ssam 	} *uap = (struct a *)u.u_ap;
64411811Ssam 	register struct inode *ip;
64511811Ssam 	struct timeval tv[2];
64611811Ssam 
64711811Ssam 	if ((ip = owner(1)) == NULL)
64811811Ssam 		return;
64911811Ssam 	u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
65011811Ssam 	if (u.u_error == 0) {
65111811Ssam 		ip->i_flag |= IACC|IUPD|ICHG;
65211811Ssam 		iupdat(ip, &tv[0], &tv[1], 0);
65311811Ssam 	}
65411811Ssam 	iput(ip);
65511811Ssam }
65611811Ssam 
6579167Ssam /*
6589167Ssam  * Flush any pending I/O.
6599167Ssam  */
6606254Sroot sync()
66137Sbill {
66237Sbill 
6638673Sroot 	update();
66437Sbill }
6657535Sroot 
6669167Ssam /*
6679167Ssam  * Truncate a file given its path name.
6689167Ssam  */
6697701Ssam truncate()
6707701Ssam {
6717701Ssam 	struct a {
6727701Ssam 		char	*fname;
6739167Ssam 		u_long	length;
6747826Sroot 	} *uap = (struct a *)u.u_ap;
6757701Ssam 	struct inode *ip;
6767701Ssam 
6779167Ssam 	ip = namei(uchar, LOOKUP, 1);
6787701Ssam 	if (ip == NULL)
6797701Ssam 		return;
6807701Ssam 	if (access(ip, IWRITE))
6817701Ssam 		goto bad;
6827701Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
6837701Ssam 		u.u_error = EISDIR;
6847701Ssam 		goto bad;
6857701Ssam 	}
6867701Ssam 	itrunc(ip, uap->length);
6877701Ssam bad:
6887701Ssam 	iput(ip);
6897701Ssam }
6907701Ssam 
6919167Ssam /*
6929167Ssam  * Truncate a file given a file descriptor.
6939167Ssam  */
6947701Ssam ftruncate()
6957701Ssam {
6967701Ssam 	struct a {
6977701Ssam 		int	fd;
6989167Ssam 		u_long	length;
6997826Sroot 	} *uap = (struct a *)u.u_ap;
7007701Ssam 	struct inode *ip;
7017701Ssam 	struct file *fp;
7027701Ssam 
70312756Ssam 	fp = getinode(uap->fd);
7047701Ssam 	if (fp == NULL)
7057701Ssam 		return;
7067701Ssam 	if ((fp->f_flag&FWRITE) == 0) {
7077701Ssam 		u.u_error = EINVAL;
7087701Ssam 		return;
7097701Ssam 	}
71012756Ssam 	ip = (struct inode *)fp->f_data;
7117701Ssam 	ilock(ip);
7127701Ssam 	itrunc(ip, uap->length);
7139167Ssam 	iunlock(ip);
7147701Ssam }
7157701Ssam 
7169167Ssam /*
7179167Ssam  * Synch an open file.
7189167Ssam  */
7199167Ssam fsync()
7209167Ssam {
7219167Ssam 	struct a {
7229167Ssam 		int	fd;
7239167Ssam 	} *uap = (struct a *)u.u_ap;
7249167Ssam 	struct inode *ip;
7259167Ssam 	struct file *fp;
7269167Ssam 
72712756Ssam 	fp = getinode(uap->fd);
7289167Ssam 	if (fp == NULL)
7299167Ssam 		return;
73012756Ssam 	ip = (struct inode *)fp->f_data;
7319167Ssam 	ilock(ip);
7329167Ssam 	syncip(ip);
7339167Ssam 	iunlock(ip);
7349167Ssam }
7359167Ssam 
7369167Ssam /*
7379167Ssam  * Rename system call.
7389167Ssam  * 	rename("foo", "bar");
7399167Ssam  * is essentially
7409167Ssam  *	unlink("bar");
7419167Ssam  *	link("foo", "bar");
7429167Ssam  *	unlink("foo");
7439167Ssam  * but ``atomically''.  Can't do full commit without saving state in the
7449167Ssam  * inode on disk which isn't feasible at this time.  Best we can do is
7459167Ssam  * always guarantee the target exists.
7469167Ssam  *
7479167Ssam  * Basic algorithm is:
7489167Ssam  *
7499167Ssam  * 1) Bump link count on source while we're linking it to the
7509167Ssam  *    target.  This also insure the inode won't be deleted out
7519167Ssam  *    from underneath us while we work.
7529167Ssam  * 2) Link source to destination.  If destination already exists,
7539167Ssam  *    delete it first.
7549167Ssam  * 3) Unlink source reference to inode if still around.
7559167Ssam  * 4) If a directory was moved and the parent of the destination
7569167Ssam  *    is different from the source, patch the ".." entry in the
7579167Ssam  *    directory.
7589167Ssam  *
7599167Ssam  * Source and destination must either both be directories, or both
7609167Ssam  * not be directories.  If target is a directory, it must be empty.
7619167Ssam  */
7627701Ssam rename()
7637701Ssam {
7647701Ssam 	struct a {
7657701Ssam 		char	*from;
7667701Ssam 		char	*to;
7677701Ssam 	} *uap;
7689167Ssam 	register struct inode *ip, *xp, *dp;
769*16655Smckusick 	struct inode *zp;
7709167Ssam 	int oldparent, parentdifferent, doingdirectory;
77110051Ssam 	int error = 0;
7727701Ssam 
7739167Ssam 	uap = (struct a *)u.u_ap;
77411641Ssam 	ip = namei(uchar, DELETE | LOCKPARENT, 0);
7759167Ssam 	if (ip == NULL)
7769167Ssam 		return;
7779167Ssam 	dp = u.u_pdir;
7789167Ssam 	oldparent = 0, doingdirectory = 0;
7799167Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
7809167Ssam 		register struct direct *d;
7819167Ssam 
7829167Ssam 		d = &u.u_dent;
7839167Ssam 		/*
78411641Ssam 		 * Avoid ".", "..", and aliases of "." for obvious reasons.
7859167Ssam 		 */
78611641Ssam 		if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
78711641Ssam 		    (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
78811641Ssam 		    (dp == ip)) {
78911641Ssam 			iput(dp);
79011641Ssam 			if (dp == ip)
79111641Ssam 				irele(ip);
79211641Ssam 			else
79310051Ssam 				iput(ip);
79411641Ssam 			u.u_error = EINVAL;
79511641Ssam 			return;
7969167Ssam 		}
7979167Ssam 		oldparent = dp->i_number;
7989167Ssam 		doingdirectory++;
7999167Ssam 	}
80011641Ssam 	iput(dp);
8019167Ssam 
8029167Ssam 	/*
8039167Ssam 	 * 1) Bump link count while we're moving stuff
8049167Ssam 	 *    around.  If we crash somewhere before
8059167Ssam 	 *    completing our work, the link count
8069167Ssam 	 *    may be wrong, but correctable.
8079167Ssam 	 */
8089167Ssam 	ip->i_nlink++;
8099167Ssam 	ip->i_flag |= ICHG;
8109167Ssam 	iupdat(ip, &time, &time, 1);
8119167Ssam 	iunlock(ip);
8129167Ssam 
8139167Ssam 	/*
8149167Ssam 	 * When the target exists, both the directory
8159167Ssam 	 * and target inodes are returned locked.
8169167Ssam 	 */
8179167Ssam 	u.u_dirp = (caddr_t)uap->to;
81815797Smckusick 	xp = namei(uchar, CREATE | LOCKPARENT | NOCACHE, 0);
81910051Ssam 	if (u.u_error) {
82010051Ssam 		error = u.u_error;
8219167Ssam 		goto out;
82210051Ssam 	}
8239167Ssam 	dp = u.u_pdir;
8249167Ssam 	/*
82511641Ssam 	 * If ".." must be changed (ie the directory gets a new
82612816Smckusick 	 * parent) then the source directory must not be in the
82712816Smckusick 	 * directory heirarchy above the target, as this would
82812816Smckusick 	 * orphan everything below the source directory. Also
82912816Smckusick 	 * the user must have write permission in the source so
83012816Smckusick 	 * as to be able to change "..". We must repeat the call
83112816Smckusick 	 * to namei, as the parent directory is unlocked by the
83212816Smckusick 	 * call to checkpath().
83311641Ssam 	 */
83411641Ssam 	parentdifferent = oldparent != dp->i_number;
83512816Smckusick 	if (doingdirectory && parentdifferent) {
83612816Smckusick 		if (access(ip, IWRITE))
83712816Smckusick 			goto bad;
83812816Smckusick 		do {
83912816Smckusick 			dp = u.u_pdir;
84012816Smckusick 			if (xp != NULL)
84112816Smckusick 				iput(xp);
84212816Smckusick 			u.u_error = checkpath(ip, dp);
84312816Smckusick 			if (u.u_error)
84412816Smckusick 				goto out;
84512816Smckusick 			u.u_dirp = (caddr_t)uap->to;
84615797Smckusick 			xp = namei(uchar, CREATE | LOCKPARENT | NOCACHE, 0);
84712816Smckusick 			if (u.u_error) {
84812816Smckusick 				error = u.u_error;
84912816Smckusick 				goto out;
85012816Smckusick 			}
85112816Smckusick 		} while (dp != u.u_pdir);
85212816Smckusick 	}
85311641Ssam 	/*
8549167Ssam 	 * 2) If target doesn't exist, link the target
8559167Ssam 	 *    to the source and unlink the source.
8569167Ssam 	 *    Otherwise, rewrite the target directory
8579167Ssam 	 *    entry to reference the source inode and
8589167Ssam 	 *    expunge the original entry's existence.
8599167Ssam 	 */
8609167Ssam 	if (xp == NULL) {
8619167Ssam 		if (dp->i_dev != ip->i_dev) {
86210051Ssam 			error = EXDEV;
8639167Ssam 			goto bad;
8649167Ssam 		}
8659167Ssam 		/*
8669167Ssam 		 * Account for ".." in directory.
8679167Ssam 		 * When source and destination have the
8689167Ssam 		 * same parent we don't fool with the
8699167Ssam 		 * link count -- this isn't required
8709167Ssam 		 * because we do a similar check below.
8719167Ssam 		 */
8729167Ssam 		if (doingdirectory && parentdifferent) {
8739167Ssam 			dp->i_nlink++;
8749167Ssam 			dp->i_flag |= ICHG;
8759167Ssam 			iupdat(dp, &time, &time, 1);
8769167Ssam 		}
87710850Ssam 		error = direnter(ip);
87810850Ssam 		if (error)
8799167Ssam 			goto out;
8809167Ssam 	} else {
8819167Ssam 		if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
88210051Ssam 			error = EXDEV;
8839167Ssam 			goto bad;
8849167Ssam 		}
8859167Ssam 		/*
88610590Ssam 		 * Short circuit rename(foo, foo).
88710590Ssam 		 */
88810590Ssam 		if (xp->i_number == ip->i_number)
88910590Ssam 			goto bad;
89010590Ssam 		/*
89110051Ssam 		 * Target must be empty if a directory
89210051Ssam 		 * and have no links to it.
8939167Ssam 		 * Also, insure source and target are
8949167Ssam 		 * compatible (both directories, or both
8959167Ssam 		 * not directories).
8969167Ssam 		 */
8979167Ssam 		if ((xp->i_mode&IFMT) == IFDIR) {
89810051Ssam 			if (!dirempty(xp) || xp->i_nlink > 2) {
89910051Ssam 				error = ENOTEMPTY;
9009167Ssam 				goto bad;
9019167Ssam 			}
9029167Ssam 			if (!doingdirectory) {
90310051Ssam 				error = ENOTDIR;
9049167Ssam 				goto bad;
9059167Ssam 			}
9069167Ssam 		} else if (doingdirectory) {
90710051Ssam 			error = EISDIR;
9089167Ssam 			goto bad;
9099167Ssam 		}
9109167Ssam 		dirrewrite(dp, ip);
91110051Ssam 		if (u.u_error) {
91210051Ssam 			error = u.u_error;
9139167Ssam 			goto bad1;
91410051Ssam 		}
9159167Ssam 		/*
91610051Ssam 		 * Adjust the link count of the target to
91710051Ssam 		 * reflect the dirrewrite above.  If this is
91810051Ssam 		 * a directory it is empty and there are
91910051Ssam 		 * no links to it, so we can squash the inode and
92010051Ssam 		 * any space associated with it.  We disallowed
92110051Ssam 		 * renaming over top of a directory with links to
92210051Ssam 		 * it above, as we've no way to determine if
92310051Ssam 		 * we've got a link or the directory itself, and
92410051Ssam 		 * if we get a link, then ".." will be screwed up.
9259167Ssam 		 */
92610051Ssam 		xp->i_nlink--;
9279167Ssam 		if (doingdirectory) {
92810051Ssam 			if (--xp->i_nlink != 0)
92910051Ssam 				panic("rename: linked directory");
9309167Ssam 			itrunc(xp, (u_long)0);
93110051Ssam 		}
9329167Ssam 		xp->i_flag |= ICHG;
9339167Ssam 		iput(xp);
93410246Ssam 		xp = NULL;
9359167Ssam 	}
9369167Ssam 
9379167Ssam 	/*
9389167Ssam 	 * 3) Unlink the source.
9399167Ssam 	 */
9409167Ssam 	u.u_dirp = uap->from;
941*16655Smckusick 	zp = namei(uchar, DELETE | LOCKPARENT, 0);
942*16655Smckusick 	dp = u.u_pdir;
9439167Ssam 	/*
9449167Ssam 	 * Insure directory entry still exists and
9459167Ssam 	 * has not changed since the start of all
9469167Ssam 	 * this.  If either has occured, forget about
94716652Ssam 	 * about deleting the original entry.
9489167Ssam 	 */
949*16655Smckusick 	if (dp != NULL && zp == ip) {
9509167Ssam 		/*
9519167Ssam 		 * If source is a directory, must adjust
9529167Ssam 		 * link count of parent directory also.
9539167Ssam 		 * If target didn't exist and source and
9549167Ssam 		 * target have the same parent, then we
9559167Ssam 		 * needn't touch the link count, it all
9569167Ssam 		 * balances out in the end.  Otherwise, we
9579167Ssam 		 * must do so to reflect deletion of ".."
9589167Ssam 		 * done above.
9599167Ssam 		 */
9609167Ssam 		if (doingdirectory && (xp != NULL || parentdifferent)) {
9619167Ssam 			dp->i_nlink--;
9629167Ssam 			dp->i_flag |= ICHG;
9639167Ssam 		}
9649167Ssam 		if (dirremove()) {
965*16655Smckusick 			zp->i_nlink--;
966*16655Smckusick 			zp->i_flag |= ICHG;
9679167Ssam 		}
96810051Ssam 		if (error == 0)		/* conservative */
96910051Ssam 			error = u.u_error;
9709167Ssam 	}
971*16655Smckusick 	if (zp != NULL)
972*16655Smckusick 		iput(zp);
9739167Ssam 	irele(ip);
9749167Ssam 	if (dp)
9759167Ssam 		iput(dp);
9769167Ssam 
9779167Ssam 	/*
9789167Ssam 	 * 4) Renaming a directory with the parent
9799167Ssam 	 *    different requires ".." to be rewritten.
9809167Ssam 	 *    The window is still there for ".." to
9819167Ssam 	 *    be inconsistent, but this is unavoidable,
9829167Ssam 	 *    and a lot shorter than when it was done
9839167Ssam 	 *    in a user process.
9849167Ssam 	 */
98510051Ssam 	if (doingdirectory && parentdifferent && error == 0) {
9869167Ssam 		struct dirtemplate dirbuf;
9879167Ssam 
9889167Ssam 		u.u_dirp = uap->to;
9899167Ssam 		ip = namei(uchar, LOOKUP | LOCKPARENT, 0);
9909167Ssam 		if (ip == NULL) {
9919167Ssam 			printf("rename: .. went away\n");
9929167Ssam 			return;
9939167Ssam 		}
9949167Ssam 		dp = u.u_pdir;
9959167Ssam 		if ((ip->i_mode&IFMT) != IFDIR) {
9969167Ssam 			printf("rename: .. not a directory\n");
9979167Ssam 			goto stuck;
9989167Ssam 		}
99910051Ssam 		error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
10009167Ssam 			sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
100110051Ssam 		if (error == 0) {
10029167Ssam 			dirbuf.dotdot_ino = dp->i_number;
100316644Ssam 			dp->i_id = ++nextinodeid;
10049167Ssam 			(void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf,
10059167Ssam 			  sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
10069167Ssam 		}
10079167Ssam stuck:
10089167Ssam 		irele(dp);
10099167Ssam 		iput(ip);
10109167Ssam 	}
101110051Ssam 	goto done;
101210051Ssam 
10139167Ssam bad:
101410246Ssam 	iput(dp);
10159167Ssam bad1:
10169167Ssam 	if (xp)
101710246Ssam 		iput(xp);
10189167Ssam out:
10199167Ssam 	ip->i_nlink--;
10209167Ssam 	ip->i_flag |= ICHG;
10219167Ssam 	irele(ip);
102210051Ssam done:
102310051Ssam 	if (error)
102410051Ssam 		u.u_error = error;
10257701Ssam }
10267701Ssam 
10277535Sroot /*
10287535Sroot  * Make a new file.
10297535Sroot  */
10307535Sroot struct inode *
10317535Sroot maknode(mode)
10327535Sroot 	int mode;
10337535Sroot {
10347535Sroot 	register struct inode *ip;
10357535Sroot 	ino_t ipref;
10367535Sroot 
10377535Sroot 	if ((mode & IFMT) == IFDIR)
10387535Sroot 		ipref = dirpref(u.u_pdir->i_fs);
10397535Sroot 	else
10407535Sroot 		ipref = u.u_pdir->i_number;
10417535Sroot 	ip = ialloc(u.u_pdir, ipref, mode);
10427535Sroot 	if (ip == NULL) {
10437535Sroot 		iput(u.u_pdir);
10447701Ssam 		return (NULL);
10457535Sroot 	}
10467701Ssam #ifdef QUOTA
10477535Sroot 	if (ip->i_dquot != NODQUOT)
10487535Sroot 		panic("maknode: dquot");
10497535Sroot #endif
10507535Sroot 	ip->i_flag |= IACC|IUPD|ICHG;
10517535Sroot 	if ((mode & IFMT) == 0)
10527535Sroot 		mode |= IFREG;
10537535Sroot 	ip->i_mode = mode & ~u.u_cmask;
10547535Sroot 	ip->i_nlink = 1;
10557535Sroot 	ip->i_uid = u.u_uid;
10567535Sroot 	ip->i_gid = u.u_pdir->i_gid;
105711811Ssam 	if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
105811811Ssam 		ip->i_mode &= ~ISGID;
10597701Ssam #ifdef QUOTA
10607535Sroot 	ip->i_dquot = inoquota(ip);
10617535Sroot #endif
10627535Sroot 
10637535Sroot 	/*
10647535Sroot 	 * Make sure inode goes to disk before directory entry.
10657535Sroot 	 */
10668673Sroot 	iupdat(ip, &time, &time, 1);
106710850Ssam 	u.u_error = direnter(ip);
10687535Sroot 	if (u.u_error) {
10697535Sroot 		/*
107010850Ssam 		 * Write error occurred trying to update directory
107110850Ssam 		 * so must deallocate the inode.
10727535Sroot 		 */
10737535Sroot 		ip->i_nlink = 0;
10747535Sroot 		ip->i_flag |= ICHG;
10757535Sroot 		iput(ip);
10767701Ssam 		return (NULL);
10777535Sroot 	}
10787701Ssam 	return (ip);
10797535Sroot }
108012756Ssam 
108112756Ssam /*
108212756Ssam  * A virgin directory (no blushing please).
108312756Ssam  */
108412756Ssam struct dirtemplate mastertemplate = {
108512756Ssam 	0, 12, 1, ".",
108612756Ssam 	0, DIRBLKSIZ - 12, 2, ".."
108712756Ssam };
108812756Ssam 
108912756Ssam /*
109012756Ssam  * Mkdir system call
109112756Ssam  */
109212756Ssam mkdir()
109312756Ssam {
109412756Ssam 	struct a {
109512756Ssam 		char	*name;
109612756Ssam 		int	dmode;
109712756Ssam 	} *uap;
109812756Ssam 	register struct inode *ip, *dp;
109912756Ssam 	struct dirtemplate dirtemplate;
110012756Ssam 
110112756Ssam 	uap = (struct a *)u.u_ap;
110212756Ssam 	ip = namei(uchar, CREATE, 0);
110312756Ssam 	if (u.u_error)
110412756Ssam 		return;
110512756Ssam 	if (ip != NULL) {
110612756Ssam 		iput(ip);
110712756Ssam 		u.u_error = EEXIST;
110812756Ssam 		return;
110912756Ssam 	}
111012756Ssam 	dp = u.u_pdir;
111112756Ssam 	uap->dmode &= 0777;
111212756Ssam 	uap->dmode |= IFDIR;
111312756Ssam 	/*
111412756Ssam 	 * Must simulate part of maknode here
111512756Ssam 	 * in order to acquire the inode, but
111612756Ssam 	 * not have it entered in the parent
111712756Ssam 	 * directory.  The entry is made later
111812756Ssam 	 * after writing "." and ".." entries out.
111912756Ssam 	 */
112012756Ssam 	ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
112112756Ssam 	if (ip == NULL) {
112212756Ssam 		iput(dp);
112312756Ssam 		return;
112412756Ssam 	}
112512756Ssam #ifdef QUOTA
112612756Ssam 	if (ip->i_dquot != NODQUOT)
112712756Ssam 		panic("mkdir: dquot");
112812756Ssam #endif
112912756Ssam 	ip->i_flag |= IACC|IUPD|ICHG;
113012756Ssam 	ip->i_mode = uap->dmode & ~u.u_cmask;
113112756Ssam 	ip->i_nlink = 2;
113212756Ssam 	ip->i_uid = u.u_uid;
113312756Ssam 	ip->i_gid = dp->i_gid;
113412756Ssam #ifdef QUOTA
113512756Ssam 	ip->i_dquot = inoquota(ip);
113612756Ssam #endif
113712756Ssam 	iupdat(ip, &time, &time, 1);
113812756Ssam 
113912756Ssam 	/*
114012756Ssam 	 * Bump link count in parent directory
114112756Ssam 	 * to reflect work done below.  Should
114212756Ssam 	 * be done before reference is created
114312756Ssam 	 * so reparation is possible if we crash.
114412756Ssam 	 */
114512756Ssam 	dp->i_nlink++;
114612756Ssam 	dp->i_flag |= ICHG;
114712756Ssam 	iupdat(dp, &time, &time, 1);
114812756Ssam 
114912756Ssam 	/*
115012756Ssam 	 * Initialize directory with "."
115112756Ssam 	 * and ".." from static template.
115212756Ssam 	 */
115312756Ssam 	dirtemplate = mastertemplate;
115412756Ssam 	dirtemplate.dot_ino = ip->i_number;
115512756Ssam 	dirtemplate.dotdot_ino = dp->i_number;
115612756Ssam 	u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
115712756Ssam 		sizeof (dirtemplate), (off_t)0, 1, (int *)0);
115812756Ssam 	if (u.u_error) {
115912756Ssam 		dp->i_nlink--;
116012756Ssam 		dp->i_flag |= ICHG;
116112756Ssam 		goto bad;
116212756Ssam 	}
116312756Ssam 	/*
116412756Ssam 	 * Directory all set up, now
116512756Ssam 	 * install the entry for it in
116612756Ssam 	 * the parent directory.
116712756Ssam 	 */
116812756Ssam 	u.u_error = direnter(ip);
116912756Ssam 	dp = NULL;
117012756Ssam 	if (u.u_error) {
117112756Ssam 		u.u_dirp = uap->name;
117215797Smckusick 		dp = namei(uchar, LOOKUP | NOCACHE, 0);
117312756Ssam 		if (dp) {
117412756Ssam 			dp->i_nlink--;
117512756Ssam 			dp->i_flag |= ICHG;
117612756Ssam 		}
117712756Ssam 	}
117812756Ssam bad:
117912756Ssam 	/*
118012756Ssam 	 * No need to do an explicit itrunc here,
118112756Ssam 	 * irele will do this for us because we set
118212756Ssam 	 * the link count to 0.
118312756Ssam 	 */
118412756Ssam 	if (u.u_error) {
118512756Ssam 		ip->i_nlink = 0;
118612756Ssam 		ip->i_flag |= ICHG;
118712756Ssam 	}
118812756Ssam 	if (dp)
118912756Ssam 		iput(dp);
119012756Ssam 	iput(ip);
119112756Ssam }
119212756Ssam 
119312756Ssam /*
119412756Ssam  * Rmdir system call.
119512756Ssam  */
119612756Ssam rmdir()
119712756Ssam {
119812756Ssam 	struct a {
119912756Ssam 		char	*name;
120012756Ssam 	};
120112756Ssam 	register struct inode *ip, *dp;
120212756Ssam 
120312756Ssam 	ip = namei(uchar, DELETE | LOCKPARENT, 0);
120412756Ssam 	if (ip == NULL)
120512756Ssam 		return;
120612756Ssam 	dp = u.u_pdir;
120712756Ssam 	/*
120812756Ssam 	 * No rmdir "." please.
120912756Ssam 	 */
121012756Ssam 	if (dp == ip) {
121112756Ssam 		irele(dp);
121212756Ssam 		iput(ip);
121312756Ssam 		u.u_error = EINVAL;
121412756Ssam 		return;
121512756Ssam 	}
121612756Ssam 	if ((ip->i_mode&IFMT) != IFDIR) {
121712756Ssam 		u.u_error = ENOTDIR;
121812756Ssam 		goto out;
121912756Ssam 	}
122012756Ssam 	/*
122112756Ssam 	 * Don't remove a mounted on directory.
122212756Ssam 	 */
122312756Ssam 	if (ip->i_dev != dp->i_dev) {
122412756Ssam 		u.u_error = EBUSY;
122512756Ssam 		goto out;
122612756Ssam 	}
122712756Ssam 	/*
122812756Ssam 	 * Verify the directory is empty (and valid).
122912756Ssam 	 * (Rmdir ".." won't be valid since
123012756Ssam 	 *  ".." will contain a reference to
123112756Ssam 	 *  the current directory and thus be
123212756Ssam 	 *  non-empty.)
123312756Ssam 	 */
123412756Ssam 	if (ip->i_nlink != 2 || !dirempty(ip)) {
123512756Ssam 		u.u_error = ENOTEMPTY;
123612756Ssam 		goto out;
123712756Ssam 	}
123812756Ssam 	/*
123912756Ssam 	 * Delete reference to directory before purging
124012756Ssam 	 * inode.  If we crash in between, the directory
124112756Ssam 	 * will be reattached to lost+found,
124212756Ssam 	 */
124312756Ssam 	if (dirremove() == 0)
124412756Ssam 		goto out;
124512756Ssam 	dp->i_nlink--;
124612756Ssam 	dp->i_flag |= ICHG;
124712756Ssam 	iput(dp);
124812756Ssam 	dp = NULL;
124912756Ssam 	/*
125012756Ssam 	 * Truncate inode.  The only stuff left
125112756Ssam 	 * in the directory is "." and "..".  The
125212756Ssam 	 * "." reference is inconsequential since
125312756Ssam 	 * we're quashing it.  The ".." reference
125412756Ssam 	 * has already been adjusted above.  We've
125512756Ssam 	 * removed the "." reference and the reference
125612756Ssam 	 * in the parent directory, but there may be
125712756Ssam 	 * other hard links so decrement by 2 and
125812756Ssam 	 * worry about them later.
125912756Ssam 	 */
126012756Ssam 	ip->i_nlink -= 2;
126112756Ssam 	itrunc(ip, (u_long)0);
126212756Ssam out:
126312756Ssam 	if (dp)
126412756Ssam 		iput(dp);
126512756Ssam 	iput(ip);
126612756Ssam }
126712756Ssam 
126812756Ssam struct file *
126912756Ssam getinode(fdes)
127012756Ssam 	int fdes;
127112756Ssam {
127216540Ssam 	struct file *fp;
127312756Ssam 
127416540Ssam 	if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
127516540Ssam 		u.u_error = EBADF;
127616540Ssam 		return ((struct file *)0);
127716540Ssam 	}
127812756Ssam 	if (fp->f_type != DTYPE_INODE) {
127912756Ssam 		u.u_error = EINVAL;
128016540Ssam 		return ((struct file *)0);
128112756Ssam 	}
128212756Ssam 	return (fp);
128312756Ssam }
128412756Ssam 
128512756Ssam /*
128612756Ssam  * mode mask for creation of files
128712756Ssam  */
128812756Ssam umask()
128912756Ssam {
129012756Ssam 	register struct a {
129112756Ssam 		int	mask;
129212756Ssam 	} *uap;
129312756Ssam 
129412756Ssam 	uap = (struct a *)u.u_ap;
129512756Ssam 	u.u_r.r_val1 = u.u_cmask;
129612756Ssam 	u.u_cmask = uap->mask & 07777;
129712756Ssam }
1298