xref: /csrg-svn/sys/ufs/lfs/lfs_vnops.c (revision 12756)
1*12756Ssam /*	lfs_vnops.c	4.57	83/05/27	*/
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"
19*12756Ssam #include "../h/mount.h"
2037Sbill 
21*12756Ssam extern	struct fileops inodeops;
22*12756Ssam struct	file *getinode();
23*12756Ssam 
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 {
78*12756Ssam 	struct a {
796254Sroot 		char	*fname;
807701Ssam 		int	mode;
81*12756Ssam 		int	crtmode;
82*12756Ssam 	} *uap = (struct a *) u.u_ap;
836254Sroot 
84*12756Ssam 	copen(uap->mode-FOPEN, uap->crtmode);
856254Sroot }
866254Sroot 
876254Sroot /*
886254Sroot  * Creat system call.
896254Sroot  */
90*12756Ssam creat()
916254Sroot {
92*12756Ssam 	struct a {
936254Sroot 		char	*fname;
946254Sroot 		int	fmode;
95*12756Ssam 	} *uap = (struct a *)u.u_ap;
966254Sroot 
97*12756Ssam 	copen(FWRITE|FCREAT|FTRUNC, uap->fmode);
986254Sroot }
996254Sroot 
1006254Sroot /*
1016254Sroot  * Common code for open and creat.
102*12756Ssam  * Check permissions, allocate an open file structure,
103*12756Ssam  * and call the device open routine if any.
1046254Sroot  */
105*12756Ssam copen(mode, arg)
106*12756Ssam 	register int mode;
107*12756Ssam 	int arg;
108*12756Ssam {
1096254Sroot 	register struct inode *ip;
1106254Sroot 	register struct file *fp;
111*12756Ssam 	int i;
1126254Sroot 
113*12756Ssam #ifdef notdef
114*12756Ssam 	if ((mode&(FREAD|FWRITE)) == 0) {
115*12756Ssam 		u.u_error = EINVAL;
116*12756Ssam 		return;
117*12756Ssam 	}
118*12756Ssam #endif
119*12756Ssam 	if (mode&FCREAT) {
120*12756Ssam 		ip = namei(uchar, CREATE, 1);
121*12756Ssam 		if (ip == NULL) {
122*12756Ssam 			if (u.u_error)
123*12756Ssam 				return;
124*12756Ssam 			ip = maknode(arg&07777&(~ISVTX));
125*12756Ssam 			if (ip == NULL)
126*12756Ssam 				return;
127*12756Ssam 			mode &= ~FTRUNC;
128*12756Ssam 		} else {
129*12756Ssam 			if (mode&FEXCL) {
130*12756Ssam 				u.u_error = EEXIST;
131*12756Ssam 				iput(ip);
132*12756Ssam 				return;
133*12756Ssam 			}
134*12756Ssam 			mode &= ~FCREAT;
135*12756Ssam 		}
136*12756Ssam 	} else {
137*12756Ssam 		ip = namei(uchar, LOOKUP, 1);
138*12756Ssam 		if (ip == NULL)
139*12756Ssam 			return;
140*12756Ssam 	}
141*12756Ssam 	if ((ip->i_mode & IFMT) == IFSOCK) {
142*12756Ssam 		u.u_error = EOPNOTSUPP;
143*12756Ssam 		goto bad;
144*12756Ssam 	}
145*12756Ssam 	if ((mode&FCREAT) == 0) {
1466254Sroot 		if (mode&FREAD)
1477701Ssam 			if (access(ip, IREAD))
1487701Ssam 				goto bad;
1496254Sroot 		if (mode&FWRITE) {
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 	}
158*12756Ssam 	fp = falloc();
159*12756Ssam 	if (fp == NULL)
160*12756Ssam 		goto bad;
161*12756Ssam 	if (mode&FTRUNC)
1629167Ssam 		itrunc(ip, (u_long)0);
1637122Smckusick 	iunlock(ip);
164*12756Ssam 	fp->f_flag = mode&FMASK;
165*12756Ssam 	fp->f_type = DTYPE_INODE;
166*12756Ssam 	fp->f_ops = &inodeops;
167*12756Ssam 	fp->f_data = (caddr_t)ip;
1686254Sroot 	i = u.u_r.r_val1;
169*12756Ssam #ifdef notdef
170*12756Ssam 	if (setjmp(&u.u_qsave)) {
171*12756Ssam 		if (u.u_error == 0)
172*12756Ssam 			u.u_error = EINTR;
173*12756Ssam 		u.u_ofile[i] = NULL;
174*12756Ssam 		closef(fp);
175*12756Ssam 		return;
176*12756Ssam 	}
177*12756Ssam #endif
1788559Sroot 	u.u_error = openi(ip, mode);
179*12756Ssam 	if (u.u_error == 0)
1806254Sroot 		return;
1816254Sroot 	u.u_ofile[i] = NULL;
1826254Sroot 	fp->f_count--;
1837142Smckusick 	irele(ip);
1847701Ssam 	return;
1857701Ssam bad:
1867701Ssam 	iput(ip);
1876254Sroot }
1886254Sroot 
1896254Sroot /*
1906254Sroot  * Mknod system call
1916254Sroot  */
1926254Sroot mknod()
1936254Sroot {
1946254Sroot 	register struct inode *ip;
1956254Sroot 	register struct a {
1966254Sroot 		char	*fname;
1976254Sroot 		int	fmode;
1986254Sroot 		int	dev;
1996254Sroot 	} *uap;
2006254Sroot 
2016254Sroot 	uap = (struct a *)u.u_ap;
202*12756Ssam 	if (!suser())
203*12756Ssam 		return;
204*12756Ssam 	ip = namei(uchar, CREATE, 0);
205*12756Ssam 	if (ip != NULL) {
206*12756Ssam 		u.u_error = EEXIST;
207*12756Ssam 		goto out;
2086254Sroot 	}
2096254Sroot 	if (u.u_error)
2106254Sroot 		return;
2116254Sroot 	ip = maknode(uap->fmode);
2126254Sroot 	if (ip == NULL)
2136254Sroot 		return;
214*12756Ssam 	switch (ip->i_mode & IFMT) {
215*12756Ssam 
216*12756Ssam 	case IFCHR:
217*12756Ssam 	case IFBLK:
218*12756Ssam 		if (uap->dev) {
219*12756Ssam 			/*
220*12756Ssam 			 * Want to be able to use this to make badblock
221*12756Ssam 			 * inodes, so don't truncate the dev number.
222*12756Ssam 			 */
223*12756Ssam 			ip->i_rdev = uap->dev;
224*12756Ssam 			ip->i_flag |= IACC|IUPD|ICHG;
225*12756Ssam 		}
2266254Sroot 	}
2276254Sroot 
2286254Sroot out:
2296254Sroot 	iput(ip);
2306254Sroot }
2316254Sroot 
2326254Sroot /*
2336254Sroot  * link system call
2346254Sroot  */
2356254Sroot link()
2366254Sroot {
2376254Sroot 	register struct inode *ip, *xp;
2386254Sroot 	register struct a {
2396254Sroot 		char	*target;
2406254Sroot 		char	*linkname;
2416254Sroot 	} *uap;
2426254Sroot 
2436254Sroot 	uap = (struct a *)u.u_ap;
2449167Ssam 	ip = namei(uchar, LOOKUP, 1); /* well, this routine is doomed anyhow */
2456254Sroot 	if (ip == NULL)
2466254Sroot 		return;
2479167Ssam 	if ((ip->i_mode&IFMT) == IFDIR && !suser()) {
2487439Sroot 		iput(ip);
2497439Sroot 		return;
2507439Sroot 	}
2516254Sroot 	ip->i_nlink++;
2526254Sroot 	ip->i_flag |= ICHG;
2538673Sroot 	iupdat(ip, &time, &time, 1);
2547122Smckusick 	iunlock(ip);
2556254Sroot 	u.u_dirp = (caddr_t)uap->linkname;
2569167Ssam 	xp = namei(uchar, CREATE, 0);
2576254Sroot 	if (xp != NULL) {
2586254Sroot 		u.u_error = EEXIST;
2596254Sroot 		iput(xp);
2606254Sroot 		goto out;
2616254Sroot 	}
2626254Sroot 	if (u.u_error)
2636254Sroot 		goto out;
2646254Sroot 	if (u.u_pdir->i_dev != ip->i_dev) {
2656254Sroot 		iput(u.u_pdir);
2666254Sroot 		u.u_error = EXDEV;
2676254Sroot 		goto out;
2686254Sroot 	}
26910850Ssam 	u.u_error = direnter(ip);
2706254Sroot out:
2716254Sroot 	if (u.u_error) {
2726254Sroot 		ip->i_nlink--;
2736254Sroot 		ip->i_flag |= ICHG;
2746254Sroot 	}
2757142Smckusick 	irele(ip);
2766254Sroot }
2776254Sroot 
2786254Sroot /*
2796254Sroot  * symlink -- make a symbolic link
2806254Sroot  */
2816254Sroot symlink()
2826254Sroot {
2836254Sroot 	register struct a {
2846254Sroot 		char	*target;
2856254Sroot 		char	*linkname;
2866254Sroot 	} *uap;
2876254Sroot 	register struct inode *ip;
2886254Sroot 	register char *tp;
2896254Sroot 	register c, nc;
2906254Sroot 
2916254Sroot 	uap = (struct a *)u.u_ap;
2926254Sroot 	tp = uap->target;
2936254Sroot 	nc = 0;
2946254Sroot 	while (c = fubyte(tp)) {
2956254Sroot 		if (c < 0) {
2966254Sroot 			u.u_error = EFAULT;
2976254Sroot 			return;
2986254Sroot 		}
2996254Sroot 		tp++;
3006254Sroot 		nc++;
3016254Sroot 	}
3026254Sroot 	u.u_dirp = uap->linkname;
3039167Ssam 	ip = namei(uchar, CREATE, 0);
3046254Sroot 	if (ip) {
3056254Sroot 		iput(ip);
3066254Sroot 		u.u_error = EEXIST;
3076254Sroot 		return;
3086254Sroot 	}
3096254Sroot 	if (u.u_error)
3106254Sroot 		return;
3116254Sroot 	ip = maknode(IFLNK | 0777);
3126254Sroot 	if (ip == NULL)
3136254Sroot 		return;
3147826Sroot 	u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0);
3159167Ssam 	/* handle u.u_error != 0 */
3166254Sroot 	iput(ip);
3176254Sroot }
3186254Sroot 
3196254Sroot /*
3206254Sroot  * Unlink system call.
3216254Sroot  * Hard to avoid races here, especially
3226254Sroot  * in unlinking directories.
3236254Sroot  */
3246254Sroot unlink()
3256254Sroot {
3266254Sroot 	struct a {
3276254Sroot 		char	*fname;
3286254Sroot 	};
3299167Ssam 	register struct inode *ip, *dp;
3306254Sroot 
3319167Ssam 	ip = namei(uchar, DELETE | LOCKPARENT, 0);
3329167Ssam 	if (ip == NULL)
3336254Sroot 		return;
3349167Ssam 	dp = u.u_pdir;
3359167Ssam 	if ((ip->i_mode&IFMT) == IFDIR && !suser())
3366254Sroot 		goto out;
3376254Sroot 	/*
3386254Sroot 	 * Don't unlink a mounted file.
3396254Sroot 	 */
3409167Ssam 	if (ip->i_dev != dp->i_dev) {
3416254Sroot 		u.u_error = EBUSY;
3426254Sroot 		goto out;
3436254Sroot 	}
3446254Sroot 	if (ip->i_flag&ITEXT)
3456254Sroot 		xrele(ip);	/* try once to free text */
3467535Sroot 	if (dirremove()) {
3477535Sroot 		ip->i_nlink--;
3487535Sroot 		ip->i_flag |= ICHG;
3496254Sroot 	}
3506254Sroot out:
3519167Ssam 	if (dp == ip)
3527142Smckusick 		irele(ip);
3537142Smckusick 	else
3547142Smckusick 		iput(ip);
3559167Ssam 	iput(dp);
3566254Sroot }
3576254Sroot 
3586254Sroot /*
3596254Sroot  * Seek system call
3606254Sroot  */
3618040Sroot lseek()
3626254Sroot {
3636254Sroot 	register struct file *fp;
3646254Sroot 	register struct a {
3657701Ssam 		int	fd;
3666254Sroot 		off_t	off;
3676254Sroot 		int	sbase;
3686254Sroot 	} *uap;
3696254Sroot 
3706254Sroot 	uap = (struct a *)u.u_ap;
371*12756Ssam 	fp = getinode(uap->fd);
3726254Sroot 	if (fp == NULL)
3736254Sroot 		return;
374*12756Ssam 	if (uap->sbase == L_INCR)
3756254Sroot 		uap->off += fp->f_offset;
376*12756Ssam 	else if (uap->sbase == L_XTND)
377*12756Ssam 		uap->off += ((struct inode *)fp->f_data)->i_size;
3786254Sroot 	fp->f_offset = uap->off;
3796254Sroot 	u.u_r.r_off = uap->off;
3806254Sroot }
3816254Sroot 
3826254Sroot /*
3836254Sroot  * Access system call
3846254Sroot  */
3856254Sroot saccess()
3866254Sroot {
3876254Sroot 	register svuid, svgid;
3886254Sroot 	register struct inode *ip;
3896254Sroot 	register struct a {
3906254Sroot 		char	*fname;
3916254Sroot 		int	fmode;
3926254Sroot 	} *uap;
3936254Sroot 
3946254Sroot 	uap = (struct a *)u.u_ap;
3956254Sroot 	svuid = u.u_uid;
3966254Sroot 	svgid = u.u_gid;
3976254Sroot 	u.u_uid = u.u_ruid;
3986254Sroot 	u.u_gid = u.u_rgid;
3999167Ssam 	ip = namei(uchar, LOOKUP, 1);
4006254Sroot 	if (ip != NULL) {
401*12756Ssam 		if ((uap->fmode&R_OK) && access(ip, IREAD))
4027701Ssam 			goto done;
403*12756Ssam 		if ((uap->fmode&W_OK) && access(ip, IWRITE))
4047701Ssam 			goto done;
405*12756Ssam 		if ((uap->fmode&X_OK) && access(ip, IEXEC))
4067701Ssam 			goto done;
4077701Ssam done:
4086254Sroot 		iput(ip);
4096254Sroot 	}
4106254Sroot 	u.u_uid = svuid;
4116254Sroot 	u.u_gid = svgid;
4126254Sroot }
4136254Sroot 
4146254Sroot /*
4156574Smckusic  * Stat system call.  This version follows links.
41637Sbill  */
41737Sbill stat()
41837Sbill {
41937Sbill 
420*12756Ssam 	stat1(1);
42137Sbill }
42237Sbill 
42337Sbill /*
4246574Smckusic  * Lstat system call.  This version does not follow links.
4255992Swnj  */
4265992Swnj lstat()
4275992Swnj {
428*12756Ssam 
429*12756Ssam 	stat1(0);
430*12756Ssam }
431*12756Ssam 
432*12756Ssam stat1(follow)
433*12756Ssam 	int follow;
434*12756Ssam {
4355992Swnj 	register struct inode *ip;
4365992Swnj 	register struct a {
4375992Swnj 		char	*fname;
438*12756Ssam 		struct stat *ub;
4395992Swnj 	} *uap;
440*12756Ssam 	struct stat sb;
4415992Swnj 
4425992Swnj 	uap = (struct a *)u.u_ap;
443*12756Ssam 	ip = namei(uchar, LOOKUP, follow);
4445992Swnj 	if (ip == NULL)
4455992Swnj 		return;
446*12756Ssam 	(void) statinode(ip, &sb);
4475992Swnj 	iput(ip);
448*12756Ssam 	u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
4495992Swnj }
4505992Swnj 
4515992Swnj /*
4525992Swnj  * Return target name of a symbolic link
45337Sbill  */
4545992Swnj readlink()
4555992Swnj {
4565992Swnj 	register struct inode *ip;
4575992Swnj 	register struct a {
4585992Swnj 		char	*name;
4595992Swnj 		char	*buf;
4605992Swnj 		int	count;
4617826Sroot 	} *uap = (struct a *)u.u_ap;
4627826Sroot 	int resid;
4635992Swnj 
4649167Ssam 	ip = namei(uchar, LOOKUP, 0);
4655992Swnj 	if (ip == NULL)
4665992Swnj 		return;
4675992Swnj 	if ((ip->i_mode&IFMT) != IFLNK) {
4685992Swnj 		u.u_error = ENXIO;
4695992Swnj 		goto out;
4705992Swnj 	}
4717826Sroot 	u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid);
4725992Swnj out:
4735992Swnj 	iput(ip);
4747826Sroot 	u.u_r.r_val1 = uap->count - resid;
4755992Swnj }
4765992Swnj 
4779167Ssam /*
4789167Ssam  * Change mode of a file given path name.
4799167Ssam  */
4806254Sroot chmod()
4815992Swnj {
4827701Ssam 	struct inode *ip;
4837701Ssam 	struct a {
4846254Sroot 		char	*fname;
4856254Sroot 		int	fmode;
4865992Swnj 	} *uap;
4875992Swnj 
4885992Swnj 	uap = (struct a *)u.u_ap;
4896254Sroot 	if ((ip = owner(1)) == NULL)
4905992Swnj 		return;
4917701Ssam 	chmod1(ip, uap->fmode);
4929167Ssam 	iput(ip);
4937701Ssam }
4947439Sroot 
4959167Ssam /*
4969167Ssam  * Change mode of a file given a file descriptor.
4979167Ssam  */
4987701Ssam fchmod()
4997701Ssam {
5007701Ssam 	struct a {
5017701Ssam 		int	fd;
5027701Ssam 		int	fmode;
5037701Ssam 	} *uap;
5047701Ssam 	register struct inode *ip;
5057701Ssam 	register struct file *fp;
5067701Ssam 
5077701Ssam 	uap = (struct a *)u.u_ap;
508*12756Ssam 	fp = getinode(uap->fd);
5097701Ssam 	if (fp == NULL)
5107701Ssam 		return;
511*12756Ssam 	ip = (struct inode *)fp->f_data;
5129167Ssam 	if (u.u_uid != ip->i_uid && !suser())
5139167Ssam 		return;
5147701Ssam 	ilock(ip);
5157701Ssam 	chmod1(ip, uap->fmode);
5169167Ssam 	iunlock(ip);
5177701Ssam }
5187701Ssam 
5199167Ssam /*
5209167Ssam  * Change the mode on a file.
5219167Ssam  * Inode must be locked before calling.
5229167Ssam  */
5237701Ssam chmod1(ip, mode)
5247701Ssam 	register struct inode *ip;
5257701Ssam 	register int mode;
5267701Ssam {
5277868Sroot 
5286254Sroot 	ip->i_mode &= ~07777;
5297439Sroot 	if (u.u_uid) {
5307701Ssam 		mode &= ~ISVTX;
53111811Ssam 		if (!groupmember(ip->i_gid))
53211811Ssam 			mode &= ~ISGID;
5337439Sroot 	}
5347701Ssam 	ip->i_mode |= mode&07777;
5356254Sroot 	ip->i_flag |= ICHG;
5366254Sroot 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
5376254Sroot 		xrele(ip);
5385992Swnj }
5395992Swnj 
5409167Ssam /*
5419167Ssam  * Set ownership given a path name.
5429167Ssam  */
5436254Sroot chown()
54437Sbill {
5457701Ssam 	struct inode *ip;
5467701Ssam 	struct a {
5476254Sroot 		char	*fname;
5486254Sroot 		int	uid;
5496254Sroot 		int	gid;
55037Sbill 	} *uap;
55137Sbill 
55237Sbill 	uap = (struct a *)u.u_ap;
55311821Ssam 	if (!suser() || (ip = owner(0)) == NULL)
55437Sbill 		return;
55511811Ssam 	u.u_error = chown1(ip, uap->uid, uap->gid);
5569167Ssam 	iput(ip);
5577701Ssam }
5587439Sroot 
5599167Ssam /*
5609167Ssam  * Set ownership given a file descriptor.
5619167Ssam  */
5627701Ssam fchown()
5637701Ssam {
5647701Ssam 	struct a {
5657701Ssam 		int	fd;
5667701Ssam 		int	uid;
5677701Ssam 		int	gid;
5687701Ssam 	} *uap;
5697701Ssam 	register struct inode *ip;
5707701Ssam 	register struct file *fp;
5717701Ssam 
5727701Ssam 	uap = (struct a *)u.u_ap;
573*12756Ssam 	fp = getinode(uap->fd);
5747701Ssam 	if (fp == NULL)
5757701Ssam 		return;
576*12756Ssam 	ip = (struct inode *)fp->f_data;
57711821Ssam 	if (!suser())
5789167Ssam 		return;
5797701Ssam 	ilock(ip);
58011811Ssam 	u.u_error = chown1(ip, uap->uid, uap->gid);
5819167Ssam 	iunlock(ip);
5827701Ssam }
5837701Ssam 
5847701Ssam /*
5857701Ssam  * Perform chown operation on inode ip;
5867701Ssam  * inode must be locked prior to call.
5877701Ssam  */
5887701Ssam chown1(ip, uid, gid)
5897701Ssam 	register struct inode *ip;
5907701Ssam 	int uid, gid;
5917701Ssam {
5927701Ssam #ifdef QUOTA
5937701Ssam 	register long change;
59411811Ssam #endif
5957701Ssam 
59611811Ssam 	if (uid == -1)
59711811Ssam 		uid = ip->i_uid;
59811811Ssam 	if (gid == -1)
59911811Ssam 		gid = ip->i_gid;
60011811Ssam #ifdef QUOTA
60112646Ssam 	if (ip->i_uid != uid)		/* this just speeds things a little */
6027482Skre 		change = 0;
60312646Ssam 	else
60412646Ssam 		change = ip->i_blocks;
60512646Ssam 	(void) chkdq(ip, -change, 1);
60612646Ssam 	(void) chkiq(ip->i_dev, ip, ip->i_uid, 1);
6077482Skre 	dqrele(ip->i_dquot);
6087482Skre #endif
60911811Ssam 	ip->i_uid = uid;
61011811Ssam 	ip->i_gid = gid;
6116254Sroot 	ip->i_flag |= ICHG;
6126254Sroot 	if (u.u_ruid != 0)
6136254Sroot 		ip->i_mode &= ~(ISUID|ISGID);
6147701Ssam #ifdef QUOTA
6157482Skre 	ip->i_dquot = inoquota(ip);
61612646Ssam 	(void) chkdq(ip, change, 1);
61712646Ssam 	(void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
61812646Ssam 	return (u.u_error);		/* should == 0 ALWAYS !! */
61912646Ssam #else
62012646Ssam 	return (0);
6217482Skre #endif
62237Sbill }
62337Sbill 
62411811Ssam #ifndef NOCOMPAT
62537Sbill /*
6266254Sroot  * Set IUPD and IACC times on file.
6276254Sroot  * Can't set ICHG.
62837Sbill  */
6298107Sroot outime()
6304828Swnj {
63137Sbill 	register struct a {
6326254Sroot 		char	*fname;
6336254Sroot 		time_t	*tptr;
63411811Ssam 	} *uap = (struct a *)u.u_ap;
6356254Sroot 	register struct inode *ip;
6366254Sroot 	time_t tv[2];
6378632Sroot 	struct timeval tv0, tv1;
63837Sbill 
6396254Sroot 	if ((ip = owner(1)) == NULL)
64037Sbill 		return;
64111811Ssam 	u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
64210001Ssam 	if (u.u_error == 0) {
6436254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
6448632Sroot 		tv0.tv_sec = tv[0]; tv0.tv_usec = 0;
6458632Sroot 		tv1.tv_sec = tv[1]; tv1.tv_usec = 0;
6468632Sroot 		iupdat(ip, &tv0, &tv1, 0);
64737Sbill 	}
64837Sbill 	iput(ip);
64937Sbill }
65011811Ssam #endif
65137Sbill 
65211811Ssam utimes()
65311811Ssam {
65411811Ssam 	register struct a {
65511811Ssam 		char	*fname;
65611811Ssam 		struct	timeval *tptr;
65711811Ssam 	} *uap = (struct a *)u.u_ap;
65811811Ssam 	register struct inode *ip;
65911811Ssam 	struct timeval tv[2];
66011811Ssam 
66111811Ssam 	if ((ip = owner(1)) == NULL)
66211811Ssam 		return;
66311811Ssam 	u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
66411811Ssam 	if (u.u_error == 0) {
66511811Ssam 		ip->i_flag |= IACC|IUPD|ICHG;
66611811Ssam 		iupdat(ip, &tv[0], &tv[1], 0);
66711811Ssam 	}
66811811Ssam 	iput(ip);
66911811Ssam }
67011811Ssam 
6719167Ssam /*
6729167Ssam  * Flush any pending I/O.
6739167Ssam  */
6746254Sroot sync()
67537Sbill {
67637Sbill 
6778673Sroot 	update();
67837Sbill }
6797535Sroot 
6809167Ssam /*
6819167Ssam  * Apply an advisory lock on a file descriptor.
6829167Ssam  */
6837701Ssam flock()
6847701Ssam {
685*12756Ssam 	register struct a {
6867701Ssam 		int	fd;
6877701Ssam 		int	how;
688*12756Ssam 	} *uap = (struct a *)u.u_ap;
6897701Ssam 	register struct file *fp;
6907701Ssam 	register int cmd, flags;
6917701Ssam 
692*12756Ssam 	fp = getinode(uap->fd);
6937701Ssam 	if (fp == NULL)
6947701Ssam 		return;
6957701Ssam 	cmd = uap->how;
6969593Ssam 	flags = u.u_pofile[uap->fd] & (UF_SHLOCK|UF_EXLOCK);
697*12756Ssam 	if (cmd&LOCK_UN) {
6987701Ssam 		if (flags == 0) {
6997701Ssam 			u.u_error = EINVAL;
7007701Ssam 			return;
7017701Ssam 		}
702*12756Ssam 		funlocki((struct inode *)fp->f_data, flags);
7039593Ssam 		u.u_pofile[uap->fd] &= ~(UF_SHLOCK|UF_EXLOCK);
7047701Ssam 		return;
7057701Ssam 	}
7067701Ssam 	/*
7077701Ssam 	 * No reason to write lock a file we've already
7087701Ssam 	 * write locked, similarly with a read lock.
7097701Ssam 	 */
710*12756Ssam 	if ((flags&UF_EXLOCK) && (cmd&LOCK_EX) ||
711*12756Ssam 	    (flags&UF_SHLOCK) && (cmd&LOCK_SH))
7127701Ssam 		return;
713*12756Ssam 	u.u_pofile[uap->fd] =
714*12756Ssam 	    flocki((struct inode *)fp->f_data, u.u_pofile[uap->fd], cmd);
7157701Ssam }
7167701Ssam 
7179167Ssam /*
7189167Ssam  * Truncate a file given its path name.
7199167Ssam  */
7207701Ssam truncate()
7217701Ssam {
7227701Ssam 	struct a {
7237701Ssam 		char	*fname;
7249167Ssam 		u_long	length;
7257826Sroot 	} *uap = (struct a *)u.u_ap;
7267701Ssam 	struct inode *ip;
7277701Ssam 
7289167Ssam 	ip = namei(uchar, LOOKUP, 1);
7297701Ssam 	if (ip == NULL)
7307701Ssam 		return;
7317701Ssam 	if (access(ip, IWRITE))
7327701Ssam 		goto bad;
7337701Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
7347701Ssam 		u.u_error = EISDIR;
7357701Ssam 		goto bad;
7367701Ssam 	}
7377701Ssam 	itrunc(ip, uap->length);
7387701Ssam bad:
7397701Ssam 	iput(ip);
7407701Ssam }
7417701Ssam 
7429167Ssam /*
7439167Ssam  * Truncate a file given a file descriptor.
7449167Ssam  */
7457701Ssam ftruncate()
7467701Ssam {
7477701Ssam 	struct a {
7487701Ssam 		int	fd;
7499167Ssam 		u_long	length;
7507826Sroot 	} *uap = (struct a *)u.u_ap;
7517701Ssam 	struct inode *ip;
7527701Ssam 	struct file *fp;
7537701Ssam 
754*12756Ssam 	fp = getinode(uap->fd);
7557701Ssam 	if (fp == NULL)
7567701Ssam 		return;
7577701Ssam 	if ((fp->f_flag&FWRITE) == 0) {
7587701Ssam 		u.u_error = EINVAL;
7597701Ssam 		return;
7607701Ssam 	}
761*12756Ssam 	ip = (struct inode *)fp->f_data;
7627701Ssam 	ilock(ip);
7637701Ssam 	itrunc(ip, uap->length);
7649167Ssam 	iunlock(ip);
7657701Ssam }
7667701Ssam 
7679167Ssam /*
7689167Ssam  * Synch an open file.
7699167Ssam  */
7709167Ssam fsync()
7719167Ssam {
7729167Ssam 	struct a {
7739167Ssam 		int	fd;
7749167Ssam 	} *uap = (struct a *)u.u_ap;
7759167Ssam 	struct inode *ip;
7769167Ssam 	struct file *fp;
7779167Ssam 
778*12756Ssam 	fp = getinode(uap->fd);
7799167Ssam 	if (fp == NULL)
7809167Ssam 		return;
781*12756Ssam 	ip = (struct inode *)fp->f_data;
7829167Ssam 	ilock(ip);
7839167Ssam 	syncip(ip);
7849167Ssam 	iunlock(ip);
7859167Ssam }
7869167Ssam 
7879167Ssam /*
7889167Ssam  * Rename system call.
7899167Ssam  * 	rename("foo", "bar");
7909167Ssam  * is essentially
7919167Ssam  *	unlink("bar");
7929167Ssam  *	link("foo", "bar");
7939167Ssam  *	unlink("foo");
7949167Ssam  * but ``atomically''.  Can't do full commit without saving state in the
7959167Ssam  * inode on disk which isn't feasible at this time.  Best we can do is
7969167Ssam  * always guarantee the target exists.
7979167Ssam  *
7989167Ssam  * Basic algorithm is:
7999167Ssam  *
8009167Ssam  * 1) Bump link count on source while we're linking it to the
8019167Ssam  *    target.  This also insure the inode won't be deleted out
8029167Ssam  *    from underneath us while we work.
8039167Ssam  * 2) Link source to destination.  If destination already exists,
8049167Ssam  *    delete it first.
8059167Ssam  * 3) Unlink source reference to inode if still around.
8069167Ssam  * 4) If a directory was moved and the parent of the destination
8079167Ssam  *    is different from the source, patch the ".." entry in the
8089167Ssam  *    directory.
8099167Ssam  *
8109167Ssam  * Source and destination must either both be directories, or both
8119167Ssam  * not be directories.  If target is a directory, it must be empty.
8129167Ssam  */
8137701Ssam rename()
8147701Ssam {
8157701Ssam 	struct a {
8167701Ssam 		char	*from;
8177701Ssam 		char	*to;
8187701Ssam 	} *uap;
8199167Ssam 	register struct inode *ip, *xp, *dp;
8209167Ssam 	int oldparent, parentdifferent, doingdirectory;
82110051Ssam 	int error = 0;
8227701Ssam 
8239167Ssam 	uap = (struct a *)u.u_ap;
82411641Ssam 	ip = namei(uchar, DELETE | LOCKPARENT, 0);
8259167Ssam 	if (ip == NULL)
8269167Ssam 		return;
8279167Ssam 	dp = u.u_pdir;
8289167Ssam 	oldparent = 0, doingdirectory = 0;
8299167Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
8309167Ssam 		register struct direct *d;
8319167Ssam 
8329167Ssam 		d = &u.u_dent;
8339167Ssam 		/*
83411641Ssam 		 * Avoid ".", "..", and aliases of "." for obvious reasons.
8359167Ssam 		 */
83611641Ssam 		if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
83711641Ssam 		    (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
83811641Ssam 		    (dp == ip)) {
83911641Ssam 			iput(dp);
84011641Ssam 			if (dp == ip)
84111641Ssam 				irele(ip);
84211641Ssam 			else
84310051Ssam 				iput(ip);
84411641Ssam 			u.u_error = EINVAL;
84511641Ssam 			return;
8469167Ssam 		}
8479167Ssam 		oldparent = dp->i_number;
8489167Ssam 		doingdirectory++;
8499167Ssam 	}
85011641Ssam 	iput(dp);
8519167Ssam 
8529167Ssam 	/*
8539167Ssam 	 * 1) Bump link count while we're moving stuff
8549167Ssam 	 *    around.  If we crash somewhere before
8559167Ssam 	 *    completing our work, the link count
8569167Ssam 	 *    may be wrong, but correctable.
8579167Ssam 	 */
8589167Ssam 	ip->i_nlink++;
8599167Ssam 	ip->i_flag |= ICHG;
8609167Ssam 	iupdat(ip, &time, &time, 1);
8619167Ssam 	iunlock(ip);
8629167Ssam 
8639167Ssam 	/*
8649167Ssam 	 * When the target exists, both the directory
8659167Ssam 	 * and target inodes are returned locked.
8669167Ssam 	 */
8679167Ssam 	u.u_dirp = (caddr_t)uap->to;
8689167Ssam 	xp = namei(uchar, CREATE | LOCKPARENT, 0);
86910051Ssam 	if (u.u_error) {
87010051Ssam 		error = u.u_error;
8719167Ssam 		goto out;
87210051Ssam 	}
8739167Ssam 	dp = u.u_pdir;
8749167Ssam 	/*
87511641Ssam 	 * If ".." must be changed (ie the directory gets a new
87611641Ssam 	 * parent) then the user must have write permission.
87711641Ssam 	 */
87811641Ssam 	parentdifferent = oldparent != dp->i_number;
87911643Ssam 	if (doingdirectory && parentdifferent && access(ip, IWRITE))
88011641Ssam 		goto bad;
88111641Ssam 	/*
8829167Ssam 	 * 2) If target doesn't exist, link the target
8839167Ssam 	 *    to the source and unlink the source.
8849167Ssam 	 *    Otherwise, rewrite the target directory
8859167Ssam 	 *    entry to reference the source inode and
8869167Ssam 	 *    expunge the original entry's existence.
8879167Ssam 	 */
8889167Ssam 	if (xp == NULL) {
8899167Ssam 		if (dp->i_dev != ip->i_dev) {
89010051Ssam 			error = EXDEV;
8919167Ssam 			goto bad;
8929167Ssam 		}
8939167Ssam 		/*
89410590Ssam 		 * Disallow rename(foo, foo/bar).
89510590Ssam 		 */
89610590Ssam 		if (dp->i_number == ip->i_number) {
89710590Ssam 			error = EEXIST;
89810590Ssam 			goto bad;
89910590Ssam 		}
90010590Ssam 		/*
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 		}
91210850Ssam 		error = direnter(ip);
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 		}
9459167Ssam 		dirrewrite(dp, ip);
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 	 */
9759167Ssam 	u.u_dirp = uap->from;
9769167Ssam 	dp = namei(uchar, DELETE, 0);
9779167Ssam 	/*
9789167Ssam 	 * Insure directory entry still exists and
9799167Ssam 	 * has not changed since the start of all
9809167Ssam 	 * this.  If either has occured, forget about
9819167Ssam 	 * about deleting the original entry and just
9829167Ssam 	 * adjust the link count in the inode.
9839167Ssam 	 */
9849167Ssam 	if (dp == NULL || u.u_dent.d_ino != ip->i_number) {
9859167Ssam 		ip->i_nlink--;
9869167Ssam 		ip->i_flag |= ICHG;
9879167Ssam 	} else {
9889167Ssam 		/*
9899167Ssam 		 * If source is a directory, must adjust
9909167Ssam 		 * link count of parent directory also.
9919167Ssam 		 * If target didn't exist and source and
9929167Ssam 		 * target have the same parent, then we
9939167Ssam 		 * needn't touch the link count, it all
9949167Ssam 		 * balances out in the end.  Otherwise, we
9959167Ssam 		 * must do so to reflect deletion of ".."
9969167Ssam 		 * done above.
9979167Ssam 		 */
9989167Ssam 		if (doingdirectory && (xp != NULL || parentdifferent)) {
9999167Ssam 			dp->i_nlink--;
10009167Ssam 			dp->i_flag |= ICHG;
10019167Ssam 		}
10029167Ssam 		if (dirremove()) {
10039167Ssam 			ip->i_nlink--;
10049167Ssam 			ip->i_flag |= ICHG;
10059167Ssam 		}
100610051Ssam 		if (error == 0)		/* conservative */
100710051Ssam 			error = u.u_error;
10089167Ssam 	}
10099167Ssam 	irele(ip);
10109167Ssam 	if (dp)
10119167Ssam 		iput(dp);
10129167Ssam 
10139167Ssam 	/*
10149167Ssam 	 * 4) Renaming a directory with the parent
10159167Ssam 	 *    different requires ".." to be rewritten.
10169167Ssam 	 *    The window is still there for ".." to
10179167Ssam 	 *    be inconsistent, but this is unavoidable,
10189167Ssam 	 *    and a lot shorter than when it was done
10199167Ssam 	 *    in a user process.
10209167Ssam 	 */
102110051Ssam 	if (doingdirectory && parentdifferent && error == 0) {
10229167Ssam 		struct dirtemplate dirbuf;
10239167Ssam 
10249167Ssam 		u.u_dirp = uap->to;
10259167Ssam 		ip = namei(uchar, LOOKUP | LOCKPARENT, 0);
10269167Ssam 		if (ip == NULL) {
10279167Ssam 			printf("rename: .. went away\n");
10289167Ssam 			return;
10299167Ssam 		}
10309167Ssam 		dp = u.u_pdir;
10319167Ssam 		if ((ip->i_mode&IFMT) != IFDIR) {
10329167Ssam 			printf("rename: .. not a directory\n");
10339167Ssam 			goto stuck;
10349167Ssam 		}
103510051Ssam 		error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
10369167Ssam 			sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
103710051Ssam 		if (error == 0) {
10389167Ssam 			dirbuf.dotdot_ino = dp->i_number;
10399167Ssam 			(void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf,
10409167Ssam 			  sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
10419167Ssam 		}
10429167Ssam stuck:
10439167Ssam 		irele(dp);
10449167Ssam 		iput(ip);
10459167Ssam 	}
104610051Ssam 	goto done;
104710051Ssam 
10489167Ssam bad:
104910246Ssam 	iput(dp);
10509167Ssam bad1:
10519167Ssam 	if (xp)
105210246Ssam 		iput(xp);
10539167Ssam out:
10549167Ssam 	ip->i_nlink--;
10559167Ssam 	ip->i_flag |= ICHG;
10569167Ssam 	irele(ip);
105710051Ssam done:
105810051Ssam 	if (error)
105910051Ssam 		u.u_error = error;
10607701Ssam }
10617701Ssam 
10627535Sroot /*
10637535Sroot  * Make a new file.
10647535Sroot  */
10657535Sroot struct inode *
10667535Sroot maknode(mode)
10677535Sroot 	int mode;
10687535Sroot {
10697535Sroot 	register struct inode *ip;
10707535Sroot 	ino_t ipref;
10717535Sroot 
10727535Sroot 	if ((mode & IFMT) == IFDIR)
10737535Sroot 		ipref = dirpref(u.u_pdir->i_fs);
10747535Sroot 	else
10757535Sroot 		ipref = u.u_pdir->i_number;
10767535Sroot 	ip = ialloc(u.u_pdir, ipref, mode);
10777535Sroot 	if (ip == NULL) {
10787535Sroot 		iput(u.u_pdir);
10797701Ssam 		return (NULL);
10807535Sroot 	}
10817701Ssam #ifdef QUOTA
10827535Sroot 	if (ip->i_dquot != NODQUOT)
10837535Sroot 		panic("maknode: dquot");
10847535Sroot #endif
10857535Sroot 	ip->i_flag |= IACC|IUPD|ICHG;
10867535Sroot 	if ((mode & IFMT) == 0)
10877535Sroot 		mode |= IFREG;
10887535Sroot 	ip->i_mode = mode & ~u.u_cmask;
10897535Sroot 	ip->i_nlink = 1;
10907535Sroot 	ip->i_uid = u.u_uid;
10917535Sroot 	ip->i_gid = u.u_pdir->i_gid;
109211811Ssam 	if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
109311811Ssam 		ip->i_mode &= ~ISGID;
10947701Ssam #ifdef QUOTA
10957535Sroot 	ip->i_dquot = inoquota(ip);
10967535Sroot #endif
10977535Sroot 
10987535Sroot 	/*
10997535Sroot 	 * Make sure inode goes to disk before directory entry.
11007535Sroot 	 */
11018673Sroot 	iupdat(ip, &time, &time, 1);
110210850Ssam 	u.u_error = direnter(ip);
11037535Sroot 	if (u.u_error) {
11047535Sroot 		/*
110510850Ssam 		 * Write error occurred trying to update directory
110610850Ssam 		 * so must deallocate the inode.
11077535Sroot 		 */
11087535Sroot 		ip->i_nlink = 0;
11097535Sroot 		ip->i_flag |= ICHG;
11107535Sroot 		iput(ip);
11117701Ssam 		return (NULL);
11127535Sroot 	}
11137701Ssam 	return (ip);
11147535Sroot }
1115*12756Ssam 
1116*12756Ssam /*
1117*12756Ssam  * A virgin directory (no blushing please).
1118*12756Ssam  */
1119*12756Ssam struct dirtemplate mastertemplate = {
1120*12756Ssam 	0, 12, 1, ".",
1121*12756Ssam 	0, DIRBLKSIZ - 12, 2, ".."
1122*12756Ssam };
1123*12756Ssam 
1124*12756Ssam /*
1125*12756Ssam  * Mkdir system call
1126*12756Ssam  */
1127*12756Ssam mkdir()
1128*12756Ssam {
1129*12756Ssam 	struct a {
1130*12756Ssam 		char	*name;
1131*12756Ssam 		int	dmode;
1132*12756Ssam 	} *uap;
1133*12756Ssam 	register struct inode *ip, *dp;
1134*12756Ssam 	struct dirtemplate dirtemplate;
1135*12756Ssam 
1136*12756Ssam 	uap = (struct a *)u.u_ap;
1137*12756Ssam 	ip = namei(uchar, CREATE, 0);
1138*12756Ssam 	if (u.u_error)
1139*12756Ssam 		return;
1140*12756Ssam 	if (ip != NULL) {
1141*12756Ssam 		iput(ip);
1142*12756Ssam 		u.u_error = EEXIST;
1143*12756Ssam 		return;
1144*12756Ssam 	}
1145*12756Ssam 	dp = u.u_pdir;
1146*12756Ssam 	uap->dmode &= 0777;
1147*12756Ssam 	uap->dmode |= IFDIR;
1148*12756Ssam 	/*
1149*12756Ssam 	 * Must simulate part of maknode here
1150*12756Ssam 	 * in order to acquire the inode, but
1151*12756Ssam 	 * not have it entered in the parent
1152*12756Ssam 	 * directory.  The entry is made later
1153*12756Ssam 	 * after writing "." and ".." entries out.
1154*12756Ssam 	 */
1155*12756Ssam 	ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
1156*12756Ssam 	if (ip == NULL) {
1157*12756Ssam 		iput(dp);
1158*12756Ssam 		return;
1159*12756Ssam 	}
1160*12756Ssam #ifdef QUOTA
1161*12756Ssam 	if (ip->i_dquot != NODQUOT)
1162*12756Ssam 		panic("mkdir: dquot");
1163*12756Ssam #endif
1164*12756Ssam 	ip->i_flag |= IACC|IUPD|ICHG;
1165*12756Ssam 	ip->i_mode = uap->dmode & ~u.u_cmask;
1166*12756Ssam 	ip->i_nlink = 2;
1167*12756Ssam 	ip->i_uid = u.u_uid;
1168*12756Ssam 	ip->i_gid = dp->i_gid;
1169*12756Ssam #ifdef QUOTA
1170*12756Ssam 	ip->i_dquot = inoquota(ip);
1171*12756Ssam #endif
1172*12756Ssam 	iupdat(ip, &time, &time, 1);
1173*12756Ssam 
1174*12756Ssam 	/*
1175*12756Ssam 	 * Bump link count in parent directory
1176*12756Ssam 	 * to reflect work done below.  Should
1177*12756Ssam 	 * be done before reference is created
1178*12756Ssam 	 * so reparation is possible if we crash.
1179*12756Ssam 	 */
1180*12756Ssam 	dp->i_nlink++;
1181*12756Ssam 	dp->i_flag |= ICHG;
1182*12756Ssam 	iupdat(dp, &time, &time, 1);
1183*12756Ssam 
1184*12756Ssam 	/*
1185*12756Ssam 	 * Initialize directory with "."
1186*12756Ssam 	 * and ".." from static template.
1187*12756Ssam 	 */
1188*12756Ssam 	dirtemplate = mastertemplate;
1189*12756Ssam 	dirtemplate.dot_ino = ip->i_number;
1190*12756Ssam 	dirtemplate.dotdot_ino = dp->i_number;
1191*12756Ssam 	u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
1192*12756Ssam 		sizeof (dirtemplate), (off_t)0, 1, (int *)0);
1193*12756Ssam 	if (u.u_error) {
1194*12756Ssam 		dp->i_nlink--;
1195*12756Ssam 		dp->i_flag |= ICHG;
1196*12756Ssam 		goto bad;
1197*12756Ssam 	}
1198*12756Ssam 	/*
1199*12756Ssam 	 * Directory all set up, now
1200*12756Ssam 	 * install the entry for it in
1201*12756Ssam 	 * the parent directory.
1202*12756Ssam 	 */
1203*12756Ssam 	u.u_error = direnter(ip);
1204*12756Ssam 	dp = NULL;
1205*12756Ssam 	if (u.u_error) {
1206*12756Ssam 		u.u_dirp = uap->name;
1207*12756Ssam 		dp = namei(uchar, LOOKUP, 0);
1208*12756Ssam 		if (dp) {
1209*12756Ssam 			dp->i_nlink--;
1210*12756Ssam 			dp->i_flag |= ICHG;
1211*12756Ssam 		}
1212*12756Ssam 	}
1213*12756Ssam bad:
1214*12756Ssam 	/*
1215*12756Ssam 	 * No need to do an explicit itrunc here,
1216*12756Ssam 	 * irele will do this for us because we set
1217*12756Ssam 	 * the link count to 0.
1218*12756Ssam 	 */
1219*12756Ssam 	if (u.u_error) {
1220*12756Ssam 		ip->i_nlink = 0;
1221*12756Ssam 		ip->i_flag |= ICHG;
1222*12756Ssam 	}
1223*12756Ssam 	if (dp)
1224*12756Ssam 		iput(dp);
1225*12756Ssam 	iput(ip);
1226*12756Ssam }
1227*12756Ssam 
1228*12756Ssam /*
1229*12756Ssam  * Rmdir system call.
1230*12756Ssam  */
1231*12756Ssam rmdir()
1232*12756Ssam {
1233*12756Ssam 	struct a {
1234*12756Ssam 		char	*name;
1235*12756Ssam 	};
1236*12756Ssam 	register struct inode *ip, *dp;
1237*12756Ssam 
1238*12756Ssam 	ip = namei(uchar, DELETE | LOCKPARENT, 0);
1239*12756Ssam 	if (ip == NULL)
1240*12756Ssam 		return;
1241*12756Ssam 	dp = u.u_pdir;
1242*12756Ssam 	/*
1243*12756Ssam 	 * No rmdir "." please.
1244*12756Ssam 	 */
1245*12756Ssam 	if (dp == ip) {
1246*12756Ssam 		irele(dp);
1247*12756Ssam 		iput(ip);
1248*12756Ssam 		u.u_error = EINVAL;
1249*12756Ssam 		return;
1250*12756Ssam 	}
1251*12756Ssam 	if ((ip->i_mode&IFMT) != IFDIR) {
1252*12756Ssam 		u.u_error = ENOTDIR;
1253*12756Ssam 		goto out;
1254*12756Ssam 	}
1255*12756Ssam 	/*
1256*12756Ssam 	 * Don't remove a mounted on directory.
1257*12756Ssam 	 */
1258*12756Ssam 	if (ip->i_dev != dp->i_dev) {
1259*12756Ssam 		u.u_error = EBUSY;
1260*12756Ssam 		goto out;
1261*12756Ssam 	}
1262*12756Ssam 	/*
1263*12756Ssam 	 * Verify the directory is empty (and valid).
1264*12756Ssam 	 * (Rmdir ".." won't be valid since
1265*12756Ssam 	 *  ".." will contain a reference to
1266*12756Ssam 	 *  the current directory and thus be
1267*12756Ssam 	 *  non-empty.)
1268*12756Ssam 	 */
1269*12756Ssam 	if (ip->i_nlink != 2 || !dirempty(ip)) {
1270*12756Ssam 		u.u_error = ENOTEMPTY;
1271*12756Ssam 		goto out;
1272*12756Ssam 	}
1273*12756Ssam 	/*
1274*12756Ssam 	 * Delete reference to directory before purging
1275*12756Ssam 	 * inode.  If we crash in between, the directory
1276*12756Ssam 	 * will be reattached to lost+found,
1277*12756Ssam 	 */
1278*12756Ssam 	if (dirremove() == 0)
1279*12756Ssam 		goto out;
1280*12756Ssam 	dp->i_nlink--;
1281*12756Ssam 	dp->i_flag |= ICHG;
1282*12756Ssam 	iput(dp);
1283*12756Ssam 	dp = NULL;
1284*12756Ssam 	/*
1285*12756Ssam 	 * Truncate inode.  The only stuff left
1286*12756Ssam 	 * in the directory is "." and "..".  The
1287*12756Ssam 	 * "." reference is inconsequential since
1288*12756Ssam 	 * we're quashing it.  The ".." reference
1289*12756Ssam 	 * has already been adjusted above.  We've
1290*12756Ssam 	 * removed the "." reference and the reference
1291*12756Ssam 	 * in the parent directory, but there may be
1292*12756Ssam 	 * other hard links so decrement by 2 and
1293*12756Ssam 	 * worry about them later.
1294*12756Ssam 	 */
1295*12756Ssam 	ip->i_nlink -= 2;
1296*12756Ssam 	itrunc(ip, (u_long)0);
1297*12756Ssam out:
1298*12756Ssam 	if (dp)
1299*12756Ssam 		iput(dp);
1300*12756Ssam 	iput(ip);
1301*12756Ssam }
1302*12756Ssam 
1303*12756Ssam struct file *
1304*12756Ssam getinode(fdes)
1305*12756Ssam 	int fdes;
1306*12756Ssam {
1307*12756Ssam 	register struct file *fp;
1308*12756Ssam 
1309*12756Ssam 	fp = getf(fdes);
1310*12756Ssam 	if (fp == 0)
1311*12756Ssam 		return (0);
1312*12756Ssam 	if (fp->f_type != DTYPE_INODE) {
1313*12756Ssam 		u.u_error = EINVAL;
1314*12756Ssam 		return (0);
1315*12756Ssam 	}
1316*12756Ssam 	return (fp);
1317*12756Ssam }
1318*12756Ssam 
1319*12756Ssam /*
1320*12756Ssam  * mode mask for creation of files
1321*12756Ssam  */
1322*12756Ssam umask()
1323*12756Ssam {
1324*12756Ssam 	register struct a {
1325*12756Ssam 		int	mask;
1326*12756Ssam 	} *uap;
1327*12756Ssam 
1328*12756Ssam 	uap = (struct a *)u.u_ap;
1329*12756Ssam 	u.u_r.r_val1 = u.u_cmask;
1330*12756Ssam 	u.u_cmask = uap->mask & 07777;
1331*12756Ssam }
1332