xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 11821)
1*11821Ssam /*	vfs_syscalls.c	4.55	83/04/01	*/
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"
157505Sroot #include "../h/descrip.h"
167826Sroot #include "../h/uio.h"
177826Sroot #include "../h/socket.h"
188632Sroot #include "../h/socketvar.h"
199167Ssam #include "../h/nami.h"
2037Sbill 
219167Ssam /*
229167Ssam  * Change current working directory (``.'').
239167Ssam  */
246254Sroot chdir()
256254Sroot {
266254Sroot 
276254Sroot 	chdirec(&u.u_cdir);
286254Sroot }
296254Sroot 
309167Ssam /*
319167Ssam  * Change notion of root (``/'') directory.
329167Ssam  */
336254Sroot chroot()
346254Sroot {
356254Sroot 
366254Sroot 	if (suser())
376254Sroot 		chdirec(&u.u_rdir);
386254Sroot }
396254Sroot 
409167Ssam /*
419167Ssam  * Common routine for chroot and chdir.
429167Ssam  */
436254Sroot chdirec(ipp)
447701Ssam 	register struct inode **ipp;
456254Sroot {
466254Sroot 	register struct inode *ip;
476254Sroot 	struct a {
486254Sroot 		char	*fname;
496254Sroot 	};
506254Sroot 
519167Ssam 	ip = namei(uchar, LOOKUP, 1);
529167Ssam 	if (ip == NULL)
536254Sroot 		return;
549167Ssam 	if ((ip->i_mode&IFMT) != IFDIR) {
556254Sroot 		u.u_error = ENOTDIR;
566254Sroot 		goto bad;
576254Sroot 	}
589167Ssam 	if (access(ip, IEXEC))
596254Sroot 		goto bad;
607122Smckusick 	iunlock(ip);
617142Smckusick 	if (*ipp)
627142Smckusick 		irele(*ipp);
636254Sroot 	*ipp = ip;
646254Sroot 	return;
656254Sroot 
666254Sroot bad:
676254Sroot 	iput(ip);
686254Sroot }
696254Sroot 
7037Sbill /*
716254Sroot  * Open system call.
726254Sroot  */
736254Sroot open()
746254Sroot {
756254Sroot 	register struct inode *ip;
766254Sroot 	register struct a {
776254Sroot 		char	*fname;
787701Ssam 		int	flags;
797701Ssam 		int	mode;
806254Sroot 	} *uap;
819167Ssam 	int checkpermissions = 1, flags;
826254Sroot 
836254Sroot 	uap = (struct a *)u.u_ap;
849167Ssam 	flags = uap->flags + 1;
859167Ssam 	if ((flags&FTRUNCATE) && (flags&FWRITE) == 0) {
869167Ssam 		u.u_error = EINVAL;
879167Ssam 		return;
889167Ssam 	}
899167Ssam 	if (flags&FCREATE) {
909167Ssam 		ip = namei(uchar, CREATE, 1);
917701Ssam 		if (ip == NULL) {
927701Ssam 			if (u.u_error)
937701Ssam 				return;
947701Ssam 			ip = maknode(uap->mode&07777&(~ISVTX));
957701Ssam 			checkpermissions = 0;
969167Ssam 			flags &= ~FTRUNCATE;
977701Ssam 		}
987701Ssam 	} else
999167Ssam 		ip = namei(uchar, LOOKUP, 1);
1006254Sroot 	if (ip == NULL)
1016254Sroot 		return;
1029167Ssam 	open1(ip, flags, checkpermissions);
1036254Sroot }
1046254Sroot 
1057701Ssam #ifndef NOCOMPAT
1066254Sroot /*
1076254Sroot  * Creat system call.
1086254Sroot  */
1097505Sroot ocreat()
1106254Sroot {
1116254Sroot 	register struct inode *ip;
1126254Sroot 	register struct a {
1136254Sroot 		char	*fname;
1146254Sroot 		int	fmode;
1156254Sroot 	} *uap;
1166254Sroot 
1176254Sroot 	uap = (struct a *)u.u_ap;
1189167Ssam 	ip = namei(uchar, CREATE, 1);
1196254Sroot 	if (ip == NULL) {
1206254Sroot 		if (u.u_error)
1216254Sroot 			return;
1226254Sroot 		ip = maknode(uap->fmode&07777&(~ISVTX));
1237701Ssam 		if (ip == NULL)
1246254Sroot 			return;
1257701Ssam 		open1(ip, FWRITE, 0);
1266254Sroot 	} else
1279167Ssam 		open1(ip, FWRITE|FTRUNCATE, 1);
1286254Sroot }
1297701Ssam #endif
1306254Sroot 
1316254Sroot /*
1326254Sroot  * Common code for open and creat.
1337701Ssam  * Check permissions (if we haven't done so already),
1347701Ssam  * allocate an open file structure, and call
1357701Ssam  * the device open routine, if any.
1366254Sroot  */
1377701Ssam open1(ip, mode, checkpermissions)
1386254Sroot 	register struct inode *ip;
1396254Sroot 	register mode;
1406254Sroot {
1416254Sroot 	register struct file *fp;
1427701Ssam 	int i, flags;
1436254Sroot 
1447701Ssam 	if (checkpermissions) {
1456254Sroot 		if (mode&FREAD)
1467701Ssam 			if (access(ip, IREAD))
1477701Ssam 				goto bad;
1486254Sroot 		if (mode&FWRITE) {
1497701Ssam 			if (access(ip, IWRITE))
1507701Ssam 				goto bad;
1517701Ssam 			if ((ip->i_mode&IFMT) == IFDIR) {
1526254Sroot 				u.u_error = EISDIR;
1537701Ssam 				goto bad;
1547701Ssam 			}
1556254Sroot 		}
1566254Sroot 	}
1577701Ssam 
1587701Ssam 	/*
1597701Ssam 	 * Check locking on inode.  Release "inode lock"
1607701Ssam 	 * while doing so in case we block inside flocki.
1617701Ssam 	 */
1627701Ssam 	flags = 0;
1639167Ssam 	if (mode&(FSHLOCK|FEXLOCK)) {
1647701Ssam 		iunlock(ip);
1657701Ssam 		flags = flocki(ip, 0, mode);
1667701Ssam 		ilock(ip);
1677701Ssam 		if (u.u_error)
1687701Ssam 			goto bad;
1697142Smckusick 	}
1707701Ssam 	if (mode&FTRUNCATE)
1719167Ssam 		itrunc(ip, (u_long)0);
1727122Smckusick 	iunlock(ip);
1736254Sroot 	if ((fp = falloc()) == NULL)
1746254Sroot 		goto out;
1757701Ssam 	fp->f_flag = mode & FMODES;
1767505Sroot 	fp->f_type = DTYPE_FILE;
1776254Sroot 	i = u.u_r.r_val1;
1786254Sroot 	fp->f_inode = ip;
1798559Sroot 	u.u_error = openi(ip, mode);
1807701Ssam 	if (u.u_error == 0) {
1817701Ssam 		u.u_pofile[i] = flags;
1826254Sroot 		return;
1837701Ssam 	}
1846254Sroot 	u.u_ofile[i] = NULL;
1856254Sroot 	fp->f_count--;
1866254Sroot out:
1877142Smckusick 	irele(ip);
1887701Ssam 	return;
1897701Ssam bad:
1907701Ssam 	iput(ip);
1916254Sroot }
1926254Sroot 
1936254Sroot /*
1946254Sroot  * Mknod system call
1956254Sroot  */
1966254Sroot mknod()
1976254Sroot {
1986254Sroot 	register struct inode *ip;
1996254Sroot 	register struct a {
2006254Sroot 		char	*fname;
2016254Sroot 		int	fmode;
2026254Sroot 		int	dev;
2036254Sroot 	} *uap;
2046254Sroot 
2056254Sroot 	uap = (struct a *)u.u_ap;
2066254Sroot 	if (suser()) {
2079167Ssam 		ip = namei(uchar, CREATE, 0);
2086254Sroot 		if (ip != NULL) {
2096254Sroot 			u.u_error = EEXIST;
2106254Sroot 			goto out;
2116254Sroot 		}
2126254Sroot 	}
2136254Sroot 	if (u.u_error)
2146254Sroot 		return;
2156254Sroot 	ip = maknode(uap->fmode);
2166254Sroot 	if (ip == NULL)
2176254Sroot 		return;
2186254Sroot 	if (uap->dev) {
2196254Sroot 		/*
2206254Sroot 		 * Want to be able to use this to make badblock
2216254Sroot 		 * inodes, so don't truncate the dev number.
2226254Sroot 		 */
2236574Smckusic 		ip->i_rdev = uap->dev;
2246254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
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;
3707701Ssam 	fp = getf(uap->fd);
3716254Sroot 	if (fp == NULL)
3726254Sroot 		return;
3737505Sroot 	if (fp->f_type == DTYPE_SOCKET) {
3746254Sroot 		u.u_error = ESPIPE;
3756254Sroot 		return;
3766254Sroot 	}
3777701Ssam 	if (uap->sbase == FSEEK_RELATIVE)
3786254Sroot 		uap->off += fp->f_offset;
3797701Ssam 	else if (uap->sbase == FSEEK_EOF)
3806254Sroot 		uap->off += fp->f_inode->i_size;
3816254Sroot 	fp->f_offset = uap->off;
3826254Sroot 	u.u_r.r_off = uap->off;
3836254Sroot }
3846254Sroot 
3856254Sroot /*
3866254Sroot  * Access system call
3876254Sroot  */
3886254Sroot saccess()
3896254Sroot {
3906254Sroot 	register svuid, svgid;
3916254Sroot 	register struct inode *ip;
3926254Sroot 	register struct a {
3936254Sroot 		char	*fname;
3946254Sroot 		int	fmode;
3956254Sroot 	} *uap;
3966254Sroot 
3976254Sroot 	uap = (struct a *)u.u_ap;
3986254Sroot 	svuid = u.u_uid;
3996254Sroot 	svgid = u.u_gid;
4006254Sroot 	u.u_uid = u.u_ruid;
4016254Sroot 	u.u_gid = u.u_rgid;
4029167Ssam 	ip = namei(uchar, LOOKUP, 1);
4036254Sroot 	if (ip != NULL) {
4049167Ssam 		if ((uap->fmode&FACCESS_READ) && access(ip, IREAD))
4057701Ssam 			goto done;
4069167Ssam 		if ((uap->fmode&FACCESS_WRITE) && access(ip, IWRITE))
4077701Ssam 			goto done;
4089167Ssam 		if ((uap->fmode&FACCESS_EXECUTE) && access(ip, IEXEC))
4097701Ssam 			goto done;
4107701Ssam done:
4116254Sroot 		iput(ip);
4126254Sroot 	}
4136254Sroot 	u.u_uid = svuid;
4146254Sroot 	u.u_gid = svgid;
4156254Sroot }
4166254Sroot 
4176254Sroot /*
41837Sbill  * the fstat system call.
41937Sbill  */
42037Sbill fstat()
42137Sbill {
42237Sbill 	register struct file *fp;
42337Sbill 	register struct a {
4247701Ssam 		int	fd;
42537Sbill 		struct stat *sb;
42637Sbill 	} *uap;
42737Sbill 
42837Sbill 	uap = (struct a *)u.u_ap;
4297701Ssam 	fp = getf(uap->fd);
4304828Swnj 	if (fp == NULL)
43137Sbill 		return;
4327505Sroot 	if (fp->f_type == DTYPE_SOCKET)
4334891Swnj 		u.u_error = sostat(fp->f_socket, uap->sb);
4344828Swnj 	else
4354828Swnj 		stat1(fp->f_inode, uap->sb);
43637Sbill }
43737Sbill 
43837Sbill /*
4396574Smckusic  * Stat system call.  This version follows links.
44037Sbill  */
44137Sbill stat()
44237Sbill {
44337Sbill 	register struct inode *ip;
44437Sbill 	register struct a {
44537Sbill 		char	*fname;
44637Sbill 		struct stat *sb;
44737Sbill 	} *uap;
44837Sbill 
44937Sbill 	uap = (struct a *)u.u_ap;
4509167Ssam 	ip = namei(uchar, LOOKUP, 1);
4514828Swnj 	if (ip == NULL)
45237Sbill 		return;
4533624Sroot 	stat1(ip, uap->sb);
45437Sbill 	iput(ip);
45537Sbill }
45637Sbill 
45737Sbill /*
4586574Smckusic  * Lstat system call.  This version does not follow links.
4595992Swnj  */
4605992Swnj lstat()
4615992Swnj {
4625992Swnj 	register struct inode *ip;
4635992Swnj 	register struct a {
4645992Swnj 		char	*fname;
4655992Swnj 		struct stat *sb;
4665992Swnj 	} *uap;
4675992Swnj 
4685992Swnj 	uap = (struct a *)u.u_ap;
4699167Ssam 	ip = namei(uchar, LOOKUP, 0);
4705992Swnj 	if (ip == NULL)
4715992Swnj 		return;
4726153Ssam 	stat1(ip, uap->sb);
4735992Swnj 	iput(ip);
4745992Swnj }
4755992Swnj 
4765992Swnj /*
47737Sbill  * The basic routine for fstat and stat:
47837Sbill  * get the inode and pass appropriate parts back.
47937Sbill  */
4803624Sroot stat1(ip, ub)
4814828Swnj 	register struct inode *ip;
4824828Swnj 	struct stat *ub;
48337Sbill {
48437Sbill 	struct stat ds;
48537Sbill 
4868673Sroot 	IUPDAT(ip, &time, &time, 0);
48737Sbill 	/*
4887023Smckusick 	 * Copy from inode table
48937Sbill 	 */
49037Sbill 	ds.st_dev = ip->i_dev;
49137Sbill 	ds.st_ino = ip->i_number;
49237Sbill 	ds.st_mode = ip->i_mode;
49337Sbill 	ds.st_nlink = ip->i_nlink;
49437Sbill 	ds.st_uid = ip->i_uid;
49537Sbill 	ds.st_gid = ip->i_gid;
4966574Smckusic 	ds.st_rdev = (dev_t)ip->i_rdev;
4973624Sroot 	ds.st_size = ip->i_size;
4986574Smckusic 	ds.st_atime = ip->i_atime;
4999903Ssam 	ds.st_spare1 = 0;
5006574Smckusic 	ds.st_mtime = ip->i_mtime;
5019903Ssam 	ds.st_spare2 = 0;
5026574Smckusic 	ds.st_ctime = ip->i_ctime;
5039903Ssam 	ds.st_spare3 = 0;
5047701Ssam 	/* this doesn't belong here */
5057701Ssam 	if ((ip->i_mode&IFMT) == IFBLK)
5067701Ssam 		ds.st_blksize = BLKDEV_IOSIZE;
5077701Ssam 	else if ((ip->i_mode&IFMT) == IFCHR)
5087701Ssam 		ds.st_blksize = MAXBSIZE;
5097701Ssam 	else
5107701Ssam 		ds.st_blksize = ip->i_fs->fs_bsize;
5119903Ssam 	ds.st_spare4[0] = ds.st_spare4[1] = ds.st_spare4[2] = 0;
51210001Ssam 	u.u_error = copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds));
51337Sbill }
51437Sbill 
51537Sbill /*
5165992Swnj  * Return target name of a symbolic link
51737Sbill  */
5185992Swnj readlink()
5195992Swnj {
5205992Swnj 	register struct inode *ip;
5215992Swnj 	register struct a {
5225992Swnj 		char	*name;
5235992Swnj 		char	*buf;
5245992Swnj 		int	count;
5257826Sroot 	} *uap = (struct a *)u.u_ap;
5267826Sroot 	int resid;
5275992Swnj 
5289167Ssam 	ip = namei(uchar, LOOKUP, 0);
5295992Swnj 	if (ip == NULL)
5305992Swnj 		return;
5315992Swnj 	if ((ip->i_mode&IFMT) != IFLNK) {
5325992Swnj 		u.u_error = ENXIO;
5335992Swnj 		goto out;
5345992Swnj 	}
5357826Sroot 	u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid);
5365992Swnj out:
5375992Swnj 	iput(ip);
5387826Sroot 	u.u_r.r_val1 = uap->count - resid;
5395992Swnj }
5405992Swnj 
5419167Ssam /*
5429167Ssam  * Change mode of a file given path name.
5439167Ssam  */
5446254Sroot chmod()
5455992Swnj {
5467701Ssam 	struct inode *ip;
5477701Ssam 	struct a {
5486254Sroot 		char	*fname;
5496254Sroot 		int	fmode;
5505992Swnj 	} *uap;
5515992Swnj 
5525992Swnj 	uap = (struct a *)u.u_ap;
5536254Sroot 	if ((ip = owner(1)) == NULL)
5545992Swnj 		return;
5557701Ssam 	chmod1(ip, uap->fmode);
5569167Ssam 	iput(ip);
5577701Ssam }
5587439Sroot 
5599167Ssam /*
5609167Ssam  * Change mode of a file given a file descriptor.
5619167Ssam  */
5627701Ssam fchmod()
5637701Ssam {
5647701Ssam 	struct a {
5657701Ssam 		int	fd;
5667701Ssam 		int	fmode;
5677701Ssam 	} *uap;
5687701Ssam 	register struct inode *ip;
5697701Ssam 	register struct file *fp;
5707701Ssam 
5717701Ssam 	uap = (struct a *)u.u_ap;
5727701Ssam 	fp = getf(uap->fd);
5737701Ssam 	if (fp == NULL)
5747701Ssam 		return;
5757701Ssam 	if (fp->f_type == DTYPE_SOCKET) {
5767701Ssam 		u.u_error = EINVAL;
5777701Ssam 		return;
5787439Sroot 	}
5797701Ssam 	ip = fp->f_inode;
5809167Ssam 	if (u.u_uid != ip->i_uid && !suser())
5819167Ssam 		return;
5827701Ssam 	ilock(ip);
5837701Ssam 	chmod1(ip, uap->fmode);
5849167Ssam 	iunlock(ip);
5857701Ssam }
5867701Ssam 
5879167Ssam /*
5889167Ssam  * Change the mode on a file.
5899167Ssam  * Inode must be locked before calling.
5909167Ssam  */
5917701Ssam chmod1(ip, mode)
5927701Ssam 	register struct inode *ip;
5937701Ssam 	register int mode;
5947701Ssam {
5957868Sroot 	register int *gp;
5967868Sroot 
5976254Sroot 	ip->i_mode &= ~07777;
5987439Sroot 	if (u.u_uid) {
5997701Ssam 		mode &= ~ISVTX;
60011811Ssam 		if (!groupmember(ip->i_gid))
60111811Ssam 			mode &= ~ISGID;
6027701Ssam #ifdef MUSH
60311811Ssam 		if (u.u_quota->q_syflags & QF_UMASK &&
6047482Skre 		    (ip->i_mode & IFMT) != IFCHR)
6057701Ssam 			mode &= ~u.u_cmask;
6067482Skre #endif
6077439Sroot 	}
6087701Ssam 	ip->i_mode |= mode&07777;
6096254Sroot 	ip->i_flag |= ICHG;
6106254Sroot 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
6116254Sroot 		xrele(ip);
6125992Swnj }
6135992Swnj 
6149167Ssam /*
6159167Ssam  * Set ownership given a path name.
6169167Ssam  */
6176254Sroot chown()
61837Sbill {
6197701Ssam 	struct inode *ip;
6207701Ssam 	struct a {
6216254Sroot 		char	*fname;
6226254Sroot 		int	uid;
6236254Sroot 		int	gid;
62437Sbill 	} *uap;
62537Sbill 
62637Sbill 	uap = (struct a *)u.u_ap;
627*11821Ssam 	if (!suser() || (ip = owner(0)) == NULL)
62837Sbill 		return;
62911811Ssam 	u.u_error = chown1(ip, uap->uid, uap->gid);
6309167Ssam 	iput(ip);
6317701Ssam }
6327439Sroot 
6339167Ssam /*
6349167Ssam  * Set ownership given a file descriptor.
6359167Ssam  */
6367701Ssam fchown()
6377701Ssam {
6387701Ssam 	struct a {
6397701Ssam 		int	fd;
6407701Ssam 		int	uid;
6417701Ssam 		int	gid;
6427701Ssam 	} *uap;
6437701Ssam 	register struct inode *ip;
6447701Ssam 	register struct file *fp;
6457701Ssam 
6467701Ssam 	uap = (struct a *)u.u_ap;
6477701Ssam 	fp = getf(uap->fd);
6487701Ssam 	if (fp == NULL)
6497701Ssam 		return;
6507701Ssam 	if (fp->f_type == DTYPE_SOCKET) {
6517701Ssam 		u.u_error = EINVAL;
6527701Ssam 		return;
6537439Sroot 	}
6547701Ssam 	ip = fp->f_inode;
655*11821Ssam 	if (!suser())
6569167Ssam 		return;
6577701Ssam 	ilock(ip);
65811811Ssam 	u.u_error = chown1(ip, uap->uid, uap->gid);
6599167Ssam 	iunlock(ip);
6607701Ssam }
6617701Ssam 
6627701Ssam /*
6637701Ssam  * Perform chown operation on inode ip;
6647701Ssam  * inode must be locked prior to call.
6657701Ssam  */
6667701Ssam chown1(ip, uid, gid)
6677701Ssam 	register struct inode *ip;
6687701Ssam 	int uid, gid;
6697701Ssam {
6707701Ssam #ifdef QUOTA
6717701Ssam 	register long change;
67211811Ssam #endif
6737701Ssam 
67411811Ssam 	if (uid == -1)
67511811Ssam 		uid = ip->i_uid;
67611811Ssam 	if (gid == -1)
67711811Ssam 		gid = ip->i_gid;
67811811Ssam #ifdef QUOTA
6797439Sroot 	/*
6807482Skre 	 * This doesn't allow for holes in files (which hopefully don't
6817482Skre 	 * happen often in files that we chown), and is not accurate anyway
6827482Skre 	 * (eg: it totally ignores 3 level indir blk files - but hopefully
6837482Skre 	 * noone who can make a file that big will have a quota)
6847482Skre 	 */
6857701Ssam 	if (ip->i_uid == uid)
6867482Skre 		change = 0;
6877482Skre 	else {
6887482Skre 		register struct fs *fs = ip->i_fs;
6897482Skre 
6907482Skre 		if (ip->i_size > (change = NDADDR * fs->fs_bsize)) {
6917482Skre 			register off_t size;
6927482Skre 
6937482Skre 			size = blkroundup(fs, ip->i_size) - change;
6947482Skre 			change += size;
6957482Skre 			change += fs->fs_bsize;
6967701Ssam 			/* this assumes NIADDR <= 2 */
6977482Skre 			if (size > NINDIR(fs) * fs->fs_bsize)
6987482Skre 				change += fs->fs_bsize;
6997482Skre 		} else
7007482Skre 			change = fragroundup(fs, ip->i_size);
7017482Skre 		change /= DEV_BSIZE;
7027482Skre 	}
7039167Ssam 	(void)chkdq(ip, -change, 1);
7049167Ssam 	(void)chkiq(ip->i_dev, ip, ip->i_uid, 1);
7057482Skre 	dqrele(ip->i_dquot);
7067482Skre #endif
70711811Ssam 	ip->i_uid = uid;
70811811Ssam 	ip->i_gid = gid;
7096254Sroot 	ip->i_flag |= ICHG;
7106254Sroot 	if (u.u_ruid != 0)
7116254Sroot 		ip->i_mode &= ~(ISUID|ISGID);
7127701Ssam #ifdef QUOTA
7137482Skre 	ip->i_dquot = inoquota(ip);
7149167Ssam 	(void)chkdq(ip, change, 1);
7159167Ssam 	(void)chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
71611811Ssam 	return (u.u_error);
7177482Skre #endif
71811811Ssam 	return (0);
71937Sbill }
72037Sbill 
72111811Ssam #ifndef NOCOMPAT
72237Sbill /*
7236254Sroot  * Set IUPD and IACC times on file.
7246254Sroot  * Can't set ICHG.
72537Sbill  */
7268107Sroot outime()
7274828Swnj {
72837Sbill 	register struct a {
7296254Sroot 		char	*fname;
7306254Sroot 		time_t	*tptr;
73111811Ssam 	} *uap = (struct a *)u.u_ap;
7326254Sroot 	register struct inode *ip;
7336254Sroot 	time_t tv[2];
7348632Sroot 	struct timeval tv0, tv1;
73537Sbill 
7366254Sroot 	if ((ip = owner(1)) == NULL)
73737Sbill 		return;
73811811Ssam 	u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
73910001Ssam 	if (u.u_error == 0) {
7406254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
7418632Sroot 		tv0.tv_sec = tv[0]; tv0.tv_usec = 0;
7428632Sroot 		tv1.tv_sec = tv[1]; tv1.tv_usec = 0;
7438632Sroot 		iupdat(ip, &tv0, &tv1, 0);
74437Sbill 	}
74537Sbill 	iput(ip);
74637Sbill }
74711811Ssam #endif
74837Sbill 
74911811Ssam utimes()
75011811Ssam {
75111811Ssam 	register struct a {
75211811Ssam 		char	*fname;
75311811Ssam 		struct	timeval *tptr;
75411811Ssam 	} *uap = (struct a *)u.u_ap;
75511811Ssam 	register struct inode *ip;
75611811Ssam 	struct timeval tv[2];
75711811Ssam 
75811811Ssam 	if ((ip = owner(1)) == NULL)
75911811Ssam 		return;
76011811Ssam 	u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
76111811Ssam 	if (u.u_error == 0) {
76211811Ssam 		ip->i_flag |= IACC|IUPD|ICHG;
76311811Ssam 		iupdat(ip, &tv[0], &tv[1], 0);
76411811Ssam 	}
76511811Ssam 	iput(ip);
76611811Ssam }
76711811Ssam 
7689167Ssam /*
7699167Ssam  * Flush any pending I/O.
7709167Ssam  */
7716254Sroot sync()
77237Sbill {
77337Sbill 
7748673Sroot 	update();
77537Sbill }
7767535Sroot 
7779167Ssam /*
7789167Ssam  * Apply an advisory lock on a file descriptor.
7799167Ssam  */
7807701Ssam flock()
7817701Ssam {
7827701Ssam 	struct a {
7837701Ssam 		int	fd;
7847701Ssam 		int	how;
7857701Ssam 	} *uap;
7867701Ssam 	register struct file *fp;
7877701Ssam 	register int cmd, flags;
7887701Ssam 
7897701Ssam 	uap = (struct a *)u.u_ap;
7907701Ssam 	fp = getf(uap->fd);
7917701Ssam 	if (fp == NULL)
7927701Ssam 		return;
7937701Ssam 	if (fp->f_type == DTYPE_SOCKET) {		/* XXX */
7947701Ssam 		u.u_error = EINVAL;
7957701Ssam 		return;
7967701Ssam 	}
7977701Ssam 	cmd = uap->how;
7989593Ssam 	flags = u.u_pofile[uap->fd] & (UF_SHLOCK|UF_EXLOCK);
7997701Ssam 	if (cmd&FUNLOCK) {
8007701Ssam 		if (flags == 0) {
8017701Ssam 			u.u_error = EINVAL;
8027701Ssam 			return;
8037701Ssam 		}
8047701Ssam 		funlocki(fp->f_inode, flags);
8059593Ssam 		u.u_pofile[uap->fd] &= ~(UF_SHLOCK|UF_EXLOCK);
8067701Ssam 		return;
8077701Ssam 	}
8087701Ssam 	/*
8097701Ssam 	 * No reason to write lock a file we've already
8107701Ssam 	 * write locked, similarly with a read lock.
8117701Ssam 	 */
8129593Ssam 	if ((flags&UF_EXLOCK) && (cmd&FEXLOCK) ||
8139593Ssam 	    (flags&UF_SHLOCK) && (cmd&FSHLOCK))
8147701Ssam 		return;
8157701Ssam 	u.u_pofile[uap->fd] = flocki(fp->f_inode, u.u_pofile[uap->fd], cmd);
8167701Ssam }
8177701Ssam 
8189167Ssam /*
8199167Ssam  * Truncate a file given its path name.
8209167Ssam  */
8217701Ssam truncate()
8227701Ssam {
8237701Ssam 	struct a {
8247701Ssam 		char	*fname;
8259167Ssam 		u_long	length;
8267826Sroot 	} *uap = (struct a *)u.u_ap;
8277701Ssam 	struct inode *ip;
8287701Ssam 
8299167Ssam 	ip = namei(uchar, LOOKUP, 1);
8307701Ssam 	if (ip == NULL)
8317701Ssam 		return;
8327701Ssam 	if (access(ip, IWRITE))
8337701Ssam 		goto bad;
8347701Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
8357701Ssam 		u.u_error = EISDIR;
8367701Ssam 		goto bad;
8377701Ssam 	}
8387701Ssam 	itrunc(ip, uap->length);
8397701Ssam bad:
8407701Ssam 	iput(ip);
8417701Ssam }
8427701Ssam 
8439167Ssam /*
8449167Ssam  * Truncate a file given a file descriptor.
8459167Ssam  */
8467701Ssam ftruncate()
8477701Ssam {
8487701Ssam 	struct a {
8497701Ssam 		int	fd;
8509167Ssam 		u_long	length;
8517826Sroot 	} *uap = (struct a *)u.u_ap;
8527701Ssam 	struct inode *ip;
8537701Ssam 	struct file *fp;
8547701Ssam 
8557701Ssam 	fp = getf(uap->fd);
8567701Ssam 	if (fp == NULL)
8577701Ssam 		return;
8587701Ssam 	if (fp->f_type == DTYPE_SOCKET) {
8597701Ssam 		u.u_error = EINVAL;
8607701Ssam 		return;
8617701Ssam 	}
8627701Ssam 	if ((fp->f_flag&FWRITE) == 0) {
8637701Ssam 		u.u_error = EINVAL;
8647701Ssam 		return;
8657701Ssam 	}
8667701Ssam 	ip = fp->f_inode;
8677701Ssam 	ilock(ip);
8687701Ssam 	itrunc(ip, uap->length);
8699167Ssam 	iunlock(ip);
8707701Ssam }
8717701Ssam 
8729167Ssam /*
8739167Ssam  * Synch an open file.
8749167Ssam  */
8759167Ssam fsync()
8769167Ssam {
8779167Ssam 	struct a {
8789167Ssam 		int	fd;
8799167Ssam 	} *uap = (struct a *)u.u_ap;
8809167Ssam 	struct inode *ip;
8819167Ssam 	struct file *fp;
8829167Ssam 
8839167Ssam 	fp = getf(uap->fd);
8849167Ssam 	if (fp == NULL)
8859167Ssam 		return;
8869167Ssam 	if (fp->f_type == DTYPE_SOCKET) {
8879167Ssam 		u.u_error = EINVAL;
8889167Ssam 		return;
8899167Ssam 	}
8909167Ssam 	ip = fp->f_inode;
8919167Ssam 	ilock(ip);
8929167Ssam 	syncip(ip);
8939167Ssam 	iunlock(ip);
8949167Ssam }
8959167Ssam 
8969167Ssam /*
8979167Ssam  * Rename system call.
8989167Ssam  * 	rename("foo", "bar");
8999167Ssam  * is essentially
9009167Ssam  *	unlink("bar");
9019167Ssam  *	link("foo", "bar");
9029167Ssam  *	unlink("foo");
9039167Ssam  * but ``atomically''.  Can't do full commit without saving state in the
9049167Ssam  * inode on disk which isn't feasible at this time.  Best we can do is
9059167Ssam  * always guarantee the target exists.
9069167Ssam  *
9079167Ssam  * Basic algorithm is:
9089167Ssam  *
9099167Ssam  * 1) Bump link count on source while we're linking it to the
9109167Ssam  *    target.  This also insure the inode won't be deleted out
9119167Ssam  *    from underneath us while we work.
9129167Ssam  * 2) Link source to destination.  If destination already exists,
9139167Ssam  *    delete it first.
9149167Ssam  * 3) Unlink source reference to inode if still around.
9159167Ssam  * 4) If a directory was moved and the parent of the destination
9169167Ssam  *    is different from the source, patch the ".." entry in the
9179167Ssam  *    directory.
9189167Ssam  *
9199167Ssam  * Source and destination must either both be directories, or both
9209167Ssam  * not be directories.  If target is a directory, it must be empty.
9219167Ssam  */
9227701Ssam rename()
9237701Ssam {
9247701Ssam 	struct a {
9257701Ssam 		char	*from;
9267701Ssam 		char	*to;
9277701Ssam 	} *uap;
9289167Ssam 	register struct inode *ip, *xp, *dp;
9299167Ssam 	int oldparent, parentdifferent, doingdirectory;
93010051Ssam 	int error = 0;
9317701Ssam 
9329167Ssam 	uap = (struct a *)u.u_ap;
93311641Ssam 	ip = namei(uchar, DELETE | LOCKPARENT, 0);
9349167Ssam 	if (ip == NULL)
9359167Ssam 		return;
9369167Ssam 	dp = u.u_pdir;
9379167Ssam 	oldparent = 0, doingdirectory = 0;
9389167Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
9399167Ssam 		register struct direct *d;
9409167Ssam 
9419167Ssam 		d = &u.u_dent;
9429167Ssam 		/*
94311641Ssam 		 * Avoid ".", "..", and aliases of "." for obvious reasons.
9449167Ssam 		 */
94511641Ssam 		if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
94611641Ssam 		    (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
94711641Ssam 		    (dp == ip)) {
94811641Ssam 			iput(dp);
94911641Ssam 			if (dp == ip)
95011641Ssam 				irele(ip);
95111641Ssam 			else
95210051Ssam 				iput(ip);
95311641Ssam 			u.u_error = EINVAL;
95411641Ssam 			return;
9559167Ssam 		}
9569167Ssam 		oldparent = dp->i_number;
9579167Ssam 		doingdirectory++;
9589167Ssam 	}
95911641Ssam 	iput(dp);
9609167Ssam 
9619167Ssam 	/*
9629167Ssam 	 * 1) Bump link count while we're moving stuff
9639167Ssam 	 *    around.  If we crash somewhere before
9649167Ssam 	 *    completing our work, the link count
9659167Ssam 	 *    may be wrong, but correctable.
9669167Ssam 	 */
9679167Ssam 	ip->i_nlink++;
9689167Ssam 	ip->i_flag |= ICHG;
9699167Ssam 	iupdat(ip, &time, &time, 1);
9709167Ssam 	iunlock(ip);
9719167Ssam 
9729167Ssam 	/*
9739167Ssam 	 * When the target exists, both the directory
9749167Ssam 	 * and target inodes are returned locked.
9759167Ssam 	 */
9769167Ssam 	u.u_dirp = (caddr_t)uap->to;
9779167Ssam 	xp = namei(uchar, CREATE | LOCKPARENT, 0);
97810051Ssam 	if (u.u_error) {
97910051Ssam 		error = u.u_error;
9809167Ssam 		goto out;
98110051Ssam 	}
9829167Ssam 	dp = u.u_pdir;
9839167Ssam 	/*
98411641Ssam 	 * If ".." must be changed (ie the directory gets a new
98511641Ssam 	 * parent) then the user must have write permission.
98611641Ssam 	 */
98711641Ssam 	parentdifferent = oldparent != dp->i_number;
98811643Ssam 	if (doingdirectory && parentdifferent && access(ip, IWRITE))
98911641Ssam 		goto bad;
99011641Ssam 	/*
9919167Ssam 	 * 2) If target doesn't exist, link the target
9929167Ssam 	 *    to the source and unlink the source.
9939167Ssam 	 *    Otherwise, rewrite the target directory
9949167Ssam 	 *    entry to reference the source inode and
9959167Ssam 	 *    expunge the original entry's existence.
9969167Ssam 	 */
9979167Ssam 	if (xp == NULL) {
9989167Ssam 		if (dp->i_dev != ip->i_dev) {
99910051Ssam 			error = EXDEV;
10009167Ssam 			goto bad;
10019167Ssam 		}
10029167Ssam 		/*
100310590Ssam 		 * Disallow rename(foo, foo/bar).
100410590Ssam 		 */
100510590Ssam 		if (dp->i_number == ip->i_number) {
100610590Ssam 			error = EEXIST;
100710590Ssam 			goto bad;
100810590Ssam 		}
100910590Ssam 		/*
10109167Ssam 		 * Account for ".." in directory.
10119167Ssam 		 * When source and destination have the
10129167Ssam 		 * same parent we don't fool with the
10139167Ssam 		 * link count -- this isn't required
10149167Ssam 		 * because we do a similar check below.
10159167Ssam 		 */
10169167Ssam 		if (doingdirectory && parentdifferent) {
10179167Ssam 			dp->i_nlink++;
10189167Ssam 			dp->i_flag |= ICHG;
10199167Ssam 			iupdat(dp, &time, &time, 1);
10209167Ssam 		}
102110850Ssam 		error = direnter(ip);
102210850Ssam 		if (error)
10239167Ssam 			goto out;
10249167Ssam 	} else {
10259167Ssam 		if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
102610051Ssam 			error = EXDEV;
10279167Ssam 			goto bad;
10289167Ssam 		}
10299167Ssam 		/*
103010590Ssam 		 * Short circuit rename(foo, foo).
103110590Ssam 		 */
103210590Ssam 		if (xp->i_number == ip->i_number)
103310590Ssam 			goto bad;
103410590Ssam 		/*
103510051Ssam 		 * Target must be empty if a directory
103610051Ssam 		 * and have no links to it.
10379167Ssam 		 * Also, insure source and target are
10389167Ssam 		 * compatible (both directories, or both
10399167Ssam 		 * not directories).
10409167Ssam 		 */
10419167Ssam 		if ((xp->i_mode&IFMT) == IFDIR) {
104210051Ssam 			if (!dirempty(xp) || xp->i_nlink > 2) {
104310051Ssam 				error = ENOTEMPTY;
10449167Ssam 				goto bad;
10459167Ssam 			}
10469167Ssam 			if (!doingdirectory) {
104710051Ssam 				error = ENOTDIR;
10489167Ssam 				goto bad;
10499167Ssam 			}
10509167Ssam 		} else if (doingdirectory) {
105110051Ssam 			error = EISDIR;
10529167Ssam 			goto bad;
10539167Ssam 		}
10549167Ssam 		dirrewrite(dp, ip);
105510051Ssam 		if (u.u_error) {
105610051Ssam 			error = u.u_error;
10579167Ssam 			goto bad1;
105810051Ssam 		}
10599167Ssam 		/*
106010051Ssam 		 * Adjust the link count of the target to
106110051Ssam 		 * reflect the dirrewrite above.  If this is
106210051Ssam 		 * a directory it is empty and there are
106310051Ssam 		 * no links to it, so we can squash the inode and
106410051Ssam 		 * any space associated with it.  We disallowed
106510051Ssam 		 * renaming over top of a directory with links to
106610051Ssam 		 * it above, as we've no way to determine if
106710051Ssam 		 * we've got a link or the directory itself, and
106810051Ssam 		 * if we get a link, then ".." will be screwed up.
10699167Ssam 		 */
107010051Ssam 		xp->i_nlink--;
10719167Ssam 		if (doingdirectory) {
107210051Ssam 			if (--xp->i_nlink != 0)
107310051Ssam 				panic("rename: linked directory");
10749167Ssam 			itrunc(xp, (u_long)0);
107510051Ssam 		}
10769167Ssam 		xp->i_flag |= ICHG;
10779167Ssam 		iput(xp);
107810246Ssam 		xp = NULL;
10799167Ssam 	}
10809167Ssam 
10819167Ssam 	/*
10829167Ssam 	 * 3) Unlink the source.
10839167Ssam 	 */
10849167Ssam 	u.u_dirp = uap->from;
10859167Ssam 	dp = namei(uchar, DELETE, 0);
10869167Ssam 	/*
10879167Ssam 	 * Insure directory entry still exists and
10889167Ssam 	 * has not changed since the start of all
10899167Ssam 	 * this.  If either has occured, forget about
10909167Ssam 	 * about deleting the original entry and just
10919167Ssam 	 * adjust the link count in the inode.
10929167Ssam 	 */
10939167Ssam 	if (dp == NULL || u.u_dent.d_ino != ip->i_number) {
10949167Ssam 		ip->i_nlink--;
10959167Ssam 		ip->i_flag |= ICHG;
10969167Ssam 	} else {
10979167Ssam 		/*
10989167Ssam 		 * If source is a directory, must adjust
10999167Ssam 		 * link count of parent directory also.
11009167Ssam 		 * If target didn't exist and source and
11019167Ssam 		 * target have the same parent, then we
11029167Ssam 		 * needn't touch the link count, it all
11039167Ssam 		 * balances out in the end.  Otherwise, we
11049167Ssam 		 * must do so to reflect deletion of ".."
11059167Ssam 		 * done above.
11069167Ssam 		 */
11079167Ssam 		if (doingdirectory && (xp != NULL || parentdifferent)) {
11089167Ssam 			dp->i_nlink--;
11099167Ssam 			dp->i_flag |= ICHG;
11109167Ssam 		}
11119167Ssam 		if (dirremove()) {
11129167Ssam 			ip->i_nlink--;
11139167Ssam 			ip->i_flag |= ICHG;
11149167Ssam 		}
111510051Ssam 		if (error == 0)		/* conservative */
111610051Ssam 			error = u.u_error;
11179167Ssam 	}
11189167Ssam 	irele(ip);
11199167Ssam 	if (dp)
11209167Ssam 		iput(dp);
11219167Ssam 
11229167Ssam 	/*
11239167Ssam 	 * 4) Renaming a directory with the parent
11249167Ssam 	 *    different requires ".." to be rewritten.
11259167Ssam 	 *    The window is still there for ".." to
11269167Ssam 	 *    be inconsistent, but this is unavoidable,
11279167Ssam 	 *    and a lot shorter than when it was done
11289167Ssam 	 *    in a user process.
11299167Ssam 	 */
113010051Ssam 	if (doingdirectory && parentdifferent && error == 0) {
11319167Ssam 		struct dirtemplate dirbuf;
11329167Ssam 
11339167Ssam 		u.u_dirp = uap->to;
11349167Ssam 		ip = namei(uchar, LOOKUP | LOCKPARENT, 0);
11359167Ssam 		if (ip == NULL) {
11369167Ssam 			printf("rename: .. went away\n");
11379167Ssam 			return;
11389167Ssam 		}
11399167Ssam 		dp = u.u_pdir;
11409167Ssam 		if ((ip->i_mode&IFMT) != IFDIR) {
11419167Ssam 			printf("rename: .. not a directory\n");
11429167Ssam 			goto stuck;
11439167Ssam 		}
114410051Ssam 		error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
11459167Ssam 			sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
114610051Ssam 		if (error == 0) {
11479167Ssam 			dirbuf.dotdot_ino = dp->i_number;
11489167Ssam 			(void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf,
11499167Ssam 			  sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
11509167Ssam 		}
11519167Ssam stuck:
11529167Ssam 		irele(dp);
11539167Ssam 		iput(ip);
11549167Ssam 	}
115510051Ssam 	goto done;
115610051Ssam 
11579167Ssam bad:
115810246Ssam 	iput(dp);
11599167Ssam bad1:
11609167Ssam 	if (xp)
116110246Ssam 		iput(xp);
11629167Ssam out:
11639167Ssam 	ip->i_nlink--;
11649167Ssam 	ip->i_flag |= ICHG;
11659167Ssam 	irele(ip);
116610051Ssam done:
116710051Ssam 	if (error)
116810051Ssam 		u.u_error = error;
11697701Ssam }
11707701Ssam 
11717535Sroot /*
11727535Sroot  * Make a new file.
11737535Sroot  */
11747535Sroot struct inode *
11757535Sroot maknode(mode)
11767535Sroot 	int mode;
11777535Sroot {
11787535Sroot 	register struct inode *ip;
11797535Sroot 	ino_t ipref;
11807535Sroot 
11817535Sroot 	if ((mode & IFMT) == IFDIR)
11827535Sroot 		ipref = dirpref(u.u_pdir->i_fs);
11837535Sroot 	else
11847535Sroot 		ipref = u.u_pdir->i_number;
11857535Sroot 	ip = ialloc(u.u_pdir, ipref, mode);
11867535Sroot 	if (ip == NULL) {
11877535Sroot 		iput(u.u_pdir);
11887701Ssam 		return (NULL);
11897535Sroot 	}
11907701Ssam #ifdef QUOTA
11917535Sroot 	if (ip->i_dquot != NODQUOT)
11927535Sroot 		panic("maknode: dquot");
11937535Sroot #endif
11947535Sroot 	ip->i_flag |= IACC|IUPD|ICHG;
11957535Sroot 	if ((mode & IFMT) == 0)
11967535Sroot 		mode |= IFREG;
11977535Sroot 	ip->i_mode = mode & ~u.u_cmask;
11987535Sroot 	ip->i_nlink = 1;
11997535Sroot 	ip->i_uid = u.u_uid;
12007535Sroot 	ip->i_gid = u.u_pdir->i_gid;
120111811Ssam 	if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
120211811Ssam 		ip->i_mode &= ~ISGID;
12037701Ssam #ifdef QUOTA
12047535Sroot 	ip->i_dquot = inoquota(ip);
12057535Sroot #endif
12067535Sroot 
12077535Sroot 	/*
12087535Sroot 	 * Make sure inode goes to disk before directory entry.
12097535Sroot 	 */
12108673Sroot 	iupdat(ip, &time, &time, 1);
121110850Ssam 	u.u_error = direnter(ip);
12127535Sroot 	if (u.u_error) {
12137535Sroot 		/*
121410850Ssam 		 * Write error occurred trying to update directory
121510850Ssam 		 * so must deallocate the inode.
12167535Sroot 		 */
12177535Sroot 		ip->i_nlink = 0;
12187535Sroot 		ip->i_flag |= ICHG;
12197535Sroot 		iput(ip);
12207701Ssam 		return (NULL);
12217535Sroot 	}
12227701Ssam 	return (ip);
12237535Sroot }
1224