xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 36614)
123405Smckusick /*
229121Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323405Smckusick  * All rights reserved.  The Berkeley software License Agreement
423405Smckusick  * specifies the terms and conditions for redistribution.
523405Smckusick  *
6*36614Sbostic  *	@(#)vfs_syscalls.c	7.4 (Berkeley) 01/24/89
723405Smckusick  */
837Sbill 
917101Sbloom #include "param.h"
1017101Sbloom #include "systm.h"
1117101Sbloom #include "dir.h"
1217101Sbloom #include "user.h"
1317101Sbloom #include "kernel.h"
1417101Sbloom #include "file.h"
1517101Sbloom #include "stat.h"
1617101Sbloom #include "inode.h"
1717101Sbloom #include "fs.h"
1817101Sbloom #include "buf.h"
1917101Sbloom #include "proc.h"
2017101Sbloom #include "quota.h"
2117101Sbloom #include "uio.h"
2217101Sbloom #include "socket.h"
2317101Sbloom #include "socketvar.h"
2417101Sbloom #include "mount.h"
2537Sbill 
2612756Ssam extern	struct fileops inodeops;
2712756Ssam struct	file *getinode();
2812756Ssam 
299167Ssam /*
309167Ssam  * Change current working directory (``.'').
319167Ssam  */
326254Sroot chdir()
336254Sroot {
346254Sroot 
356254Sroot 	chdirec(&u.u_cdir);
366254Sroot }
376254Sroot 
389167Ssam /*
399167Ssam  * Change notion of root (``/'') directory.
409167Ssam  */
416254Sroot chroot()
426254Sroot {
436254Sroot 
446254Sroot 	if (suser())
456254Sroot 		chdirec(&u.u_rdir);
466254Sroot }
476254Sroot 
489167Ssam /*
499167Ssam  * Common routine for chroot and chdir.
509167Ssam  */
516254Sroot chdirec(ipp)
527701Ssam 	register struct inode **ipp;
536254Sroot {
546254Sroot 	register struct inode *ip;
556254Sroot 	struct a {
566254Sroot 		char	*fname;
5716694Smckusick 	} *uap = (struct a *)u.u_ap;
5816694Smckusick 	register struct nameidata *ndp = &u.u_nd;
596254Sroot 
6016694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
6116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
6216694Smckusick 	ndp->ni_dirp = uap->fname;
6316694Smckusick 	ip = namei(ndp);
649167Ssam 	if (ip == NULL)
656254Sroot 		return;
669167Ssam 	if ((ip->i_mode&IFMT) != IFDIR) {
676254Sroot 		u.u_error = ENOTDIR;
686254Sroot 		goto bad;
696254Sroot 	}
709167Ssam 	if (access(ip, IEXEC))
716254Sroot 		goto bad;
7216664Smckusick 	IUNLOCK(ip);
737142Smckusick 	if (*ipp)
747142Smckusick 		irele(*ipp);
756254Sroot 	*ipp = ip;
766254Sroot 	return;
776254Sroot 
786254Sroot bad:
796254Sroot 	iput(ip);
806254Sroot }
816254Sroot 
8237Sbill /*
836254Sroot  * Open system call.
846254Sroot  */
856254Sroot open()
866254Sroot {
8712756Ssam 	struct a {
886254Sroot 		char	*fname;
897701Ssam 		int	mode;
9012756Ssam 		int	crtmode;
9112756Ssam 	} *uap = (struct a *) u.u_ap;
926254Sroot 
9316694Smckusick 	copen(uap->mode-FOPEN, uap->crtmode, uap->fname);
946254Sroot }
956254Sroot 
966254Sroot /*
976254Sroot  * Creat system call.
986254Sroot  */
9912756Ssam creat()
1006254Sroot {
10112756Ssam 	struct a {
1026254Sroot 		char	*fname;
1036254Sroot 		int	fmode;
10412756Ssam 	} *uap = (struct a *)u.u_ap;
1056254Sroot 
10616694Smckusick 	copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname);
1076254Sroot }
1086254Sroot 
1096254Sroot /*
1106254Sroot  * Common code for open and creat.
11112756Ssam  * Check permissions, allocate an open file structure,
11212756Ssam  * and call the device open routine if any.
1136254Sroot  */
11416694Smckusick copen(mode, arg, fname)
11512756Ssam 	register int mode;
11612756Ssam 	int arg;
11716694Smckusick 	caddr_t fname;
11812756Ssam {
1196254Sroot 	register struct inode *ip;
1206254Sroot 	register struct file *fp;
12116694Smckusick 	register struct nameidata *ndp = &u.u_nd;
12224543Smckusick 	int indx;
1236254Sroot 
12424543Smckusick 	fp = falloc();
12524543Smckusick 	if (fp == NULL)
12612756Ssam 		return;
12724543Smckusick 	indx = u.u_r.r_val1;
12816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
12916694Smckusick 	ndp->ni_dirp = fname;
13012756Ssam 	if (mode&FCREAT) {
13118416Smckusick 		if (mode & FEXCL)
13218416Smckusick 			ndp->ni_nameiop = CREATE;
13318416Smckusick 		else
13418416Smckusick 			ndp->ni_nameiop = CREATE | FOLLOW;
13516694Smckusick 		ip = namei(ndp);
13612756Ssam 		if (ip == NULL) {
13712756Ssam 			if (u.u_error)
13824543Smckusick 				goto bad1;
13916694Smckusick 			ip = maknode(arg&07777&(~ISVTX), ndp);
14012756Ssam 			if (ip == NULL)
14124543Smckusick 				goto bad1;
14212756Ssam 			mode &= ~FTRUNC;
14312756Ssam 		} else {
14412756Ssam 			if (mode&FEXCL) {
14512756Ssam 				u.u_error = EEXIST;
14624543Smckusick 				goto bad;
14712756Ssam 			}
14812756Ssam 			mode &= ~FCREAT;
14912756Ssam 		}
15012756Ssam 	} else {
15116694Smckusick 		ndp->ni_nameiop = LOOKUP | FOLLOW;
15216694Smckusick 		ip = namei(ndp);
15312756Ssam 		if (ip == NULL)
15424543Smckusick 			goto bad1;
15512756Ssam 	}
15612756Ssam 	if ((ip->i_mode & IFMT) == IFSOCK) {
15712756Ssam 		u.u_error = EOPNOTSUPP;
15812756Ssam 		goto bad;
15912756Ssam 	}
16012756Ssam 	if ((mode&FCREAT) == 0) {
1616254Sroot 		if (mode&FREAD)
1627701Ssam 			if (access(ip, IREAD))
1637701Ssam 				goto bad;
16416032Skarels 		if (mode&(FWRITE|FTRUNC)) {
1657701Ssam 			if (access(ip, IWRITE))
1667701Ssam 				goto bad;
1677701Ssam 			if ((ip->i_mode&IFMT) == IFDIR) {
1686254Sroot 				u.u_error = EISDIR;
1697701Ssam 				goto bad;
1707701Ssam 			}
1716254Sroot 		}
1726254Sroot 	}
17312756Ssam 	if (mode&FTRUNC)
1749167Ssam 		itrunc(ip, (u_long)0);
17516664Smckusick 	IUNLOCK(ip);
17612756Ssam 	fp->f_flag = mode&FMASK;
17712756Ssam 	fp->f_type = DTYPE_INODE;
17812756Ssam 	fp->f_ops = &inodeops;
17912756Ssam 	fp->f_data = (caddr_t)ip;
18012756Ssam 	if (setjmp(&u.u_qsave)) {
18112756Ssam 		if (u.u_error == 0)
18212756Ssam 			u.u_error = EINTR;
18324543Smckusick 		u.u_ofile[indx] = NULL;
18412756Ssam 		closef(fp);
18512756Ssam 		return;
18612756Ssam 	}
1878559Sroot 	u.u_error = openi(ip, mode);
18812756Ssam 	if (u.u_error == 0)
1896254Sroot 		return;
19024543Smckusick 	ILOCK(ip);
1917701Ssam bad:
1927701Ssam 	iput(ip);
19324543Smckusick bad1:
19424543Smckusick 	u.u_ofile[indx] = NULL;
19524543Smckusick 	fp->f_count--;
1966254Sroot }
1976254Sroot 
1986254Sroot /*
1996254Sroot  * Mknod system call
2006254Sroot  */
2016254Sroot mknod()
2026254Sroot {
2036254Sroot 	register struct inode *ip;
2046254Sroot 	register struct a {
2056254Sroot 		char	*fname;
2066254Sroot 		int	fmode;
2076254Sroot 		int	dev;
20816694Smckusick 	} *uap = (struct a *)u.u_ap;
20916694Smckusick 	register struct nameidata *ndp = &u.u_nd;
2106254Sroot 
21112756Ssam 	if (!suser())
21212756Ssam 		return;
21316694Smckusick 	ndp->ni_nameiop = CREATE;
21416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
21516694Smckusick 	ndp->ni_dirp = uap->fname;
21616694Smckusick 	ip = namei(ndp);
21712756Ssam 	if (ip != NULL) {
21812756Ssam 		u.u_error = EEXIST;
21912756Ssam 		goto out;
2206254Sroot 	}
2216254Sroot 	if (u.u_error)
2226254Sroot 		return;
22316694Smckusick 	ip = maknode(uap->fmode, ndp);
2246254Sroot 	if (ip == NULL)
2256254Sroot 		return;
22612756Ssam 	switch (ip->i_mode & IFMT) {
22712756Ssam 
22815093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
22912756Ssam 	case IFCHR:
23012756Ssam 	case IFBLK:
23112756Ssam 		if (uap->dev) {
23212756Ssam 			/*
23312756Ssam 			 * Want to be able to use this to make badblock
23412756Ssam 			 * inodes, so don't truncate the dev number.
23512756Ssam 			 */
23612756Ssam 			ip->i_rdev = uap->dev;
23712756Ssam 			ip->i_flag |= IACC|IUPD|ICHG;
23812756Ssam 		}
2396254Sroot 	}
2406254Sroot 
2416254Sroot out:
2426254Sroot 	iput(ip);
2436254Sroot }
2446254Sroot 
2456254Sroot /*
2466254Sroot  * link system call
2476254Sroot  */
2486254Sroot link()
2496254Sroot {
2506254Sroot 	register struct inode *ip, *xp;
2516254Sroot 	register struct a {
2526254Sroot 		char	*target;
2536254Sroot 		char	*linkname;
25416694Smckusick 	} *uap = (struct a *)u.u_ap;
25516694Smckusick 	register struct nameidata *ndp = &u.u_nd;
2566254Sroot 
25716694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
25816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
25916694Smckusick 	ndp->ni_dirp = uap->target;
26016694Smckusick 	ip = namei(ndp);	/* well, this routine is doomed anyhow */
2616254Sroot 	if (ip == NULL)
2626254Sroot 		return;
2639167Ssam 	if ((ip->i_mode&IFMT) == IFDIR && !suser()) {
2647439Sroot 		iput(ip);
2657439Sroot 		return;
2667439Sroot 	}
2676254Sroot 	ip->i_nlink++;
2686254Sroot 	ip->i_flag |= ICHG;
2698673Sroot 	iupdat(ip, &time, &time, 1);
27016664Smckusick 	IUNLOCK(ip);
27116694Smckusick 	ndp->ni_nameiop = CREATE;
27216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
27316694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
27416694Smckusick 	xp = namei(ndp);
2756254Sroot 	if (xp != NULL) {
2766254Sroot 		u.u_error = EEXIST;
2776254Sroot 		iput(xp);
2786254Sroot 		goto out;
2796254Sroot 	}
2806254Sroot 	if (u.u_error)
2816254Sroot 		goto out;
28216694Smckusick 	if (ndp->ni_pdir->i_dev != ip->i_dev) {
28316694Smckusick 		iput(ndp->ni_pdir);
2846254Sroot 		u.u_error = EXDEV;
2856254Sroot 		goto out;
2866254Sroot 	}
28716694Smckusick 	u.u_error = direnter(ip, ndp);
2886254Sroot out:
2896254Sroot 	if (u.u_error) {
2906254Sroot 		ip->i_nlink--;
2916254Sroot 		ip->i_flag |= ICHG;
2926254Sroot 	}
2937142Smckusick 	irele(ip);
2946254Sroot }
2956254Sroot 
2966254Sroot /*
2976254Sroot  * symlink -- make a symbolic link
2986254Sroot  */
2996254Sroot symlink()
3006254Sroot {
3016254Sroot 	register struct a {
3026254Sroot 		char	*target;
3036254Sroot 		char	*linkname;
30416694Smckusick 	} *uap = (struct a *)u.u_ap;
3056254Sroot 	register struct inode *ip;
3066254Sroot 	register char *tp;
3076254Sroot 	register c, nc;
30816694Smckusick 	register struct nameidata *ndp = &u.u_nd;
3096254Sroot 
3106254Sroot 	tp = uap->target;
3116254Sroot 	nc = 0;
3126254Sroot 	while (c = fubyte(tp)) {
3136254Sroot 		if (c < 0) {
3146254Sroot 			u.u_error = EFAULT;
3156254Sroot 			return;
3166254Sroot 		}
3176254Sroot 		tp++;
3186254Sroot 		nc++;
3196254Sroot 	}
32016694Smckusick 	ndp->ni_nameiop = CREATE;
32116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
32216694Smckusick 	ndp->ni_dirp = uap->linkname;
32316694Smckusick 	ip = namei(ndp);
3246254Sroot 	if (ip) {
3256254Sroot 		iput(ip);
3266254Sroot 		u.u_error = EEXIST;
3276254Sroot 		return;
3286254Sroot 	}
3296254Sroot 	if (u.u_error)
3306254Sroot 		return;
33116694Smckusick 	ip = maknode(IFLNK | 0777, ndp);
3326254Sroot 	if (ip == NULL)
3336254Sroot 		return;
33426361Skarels 	u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, (off_t)0, 0,
33526361Skarels 	    (int *)0);
3369167Ssam 	/* handle u.u_error != 0 */
3376254Sroot 	iput(ip);
3386254Sroot }
3396254Sroot 
3406254Sroot /*
3416254Sroot  * Unlink system call.
3426254Sroot  * Hard to avoid races here, especially
3436254Sroot  * in unlinking directories.
3446254Sroot  */
3456254Sroot unlink()
3466254Sroot {
3476254Sroot 	struct a {
3486254Sroot 		char	*fname;
34916694Smckusick 	} *uap = (struct a *)u.u_ap;
3509167Ssam 	register struct inode *ip, *dp;
35116694Smckusick 	register struct nameidata *ndp = &u.u_nd;
3526254Sroot 
35316694Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT;
35416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
35516694Smckusick 	ndp->ni_dirp = uap->fname;
35616694Smckusick 	ip = namei(ndp);
3579167Ssam 	if (ip == NULL)
3586254Sroot 		return;
35916694Smckusick 	dp = ndp->ni_pdir;
3609167Ssam 	if ((ip->i_mode&IFMT) == IFDIR && !suser())
3616254Sroot 		goto out;
3626254Sroot 	/*
3636254Sroot 	 * Don't unlink a mounted file.
3646254Sroot 	 */
3659167Ssam 	if (ip->i_dev != dp->i_dev) {
3666254Sroot 		u.u_error = EBUSY;
3676254Sroot 		goto out;
3686254Sroot 	}
3696254Sroot 	if (ip->i_flag&ITEXT)
3706254Sroot 		xrele(ip);	/* try once to free text */
37116694Smckusick 	if (dirremove(ndp)) {
3727535Sroot 		ip->i_nlink--;
3737535Sroot 		ip->i_flag |= ICHG;
3746254Sroot 	}
3756254Sroot out:
3769167Ssam 	if (dp == ip)
3777142Smckusick 		irele(ip);
3787142Smckusick 	else
3797142Smckusick 		iput(ip);
3809167Ssam 	iput(dp);
3816254Sroot }
3826254Sroot 
3836254Sroot /*
3846254Sroot  * Seek system call
3856254Sroot  */
3868040Sroot lseek()
3876254Sroot {
3886254Sroot 	register struct file *fp;
3896254Sroot 	register struct a {
3907701Ssam 		int	fd;
3916254Sroot 		off_t	off;
3926254Sroot 		int	sbase;
39316694Smckusick 	} *uap = (struct a *)u.u_ap;
3946254Sroot 
39516540Ssam 	GETF(fp, uap->fd);
39616540Ssam 	if (fp->f_type != DTYPE_INODE) {
39716540Ssam 		u.u_error = ESPIPE;
3986254Sroot 		return;
39916540Ssam 	}
40013878Ssam 	switch (uap->sbase) {
40113878Ssam 
40213878Ssam 	case L_INCR:
40313878Ssam 		fp->f_offset += uap->off;
40413878Ssam 		break;
40513878Ssam 
40613878Ssam 	case L_XTND:
40713878Ssam 		fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
40813878Ssam 		break;
40913878Ssam 
41013878Ssam 	case L_SET:
41113878Ssam 		fp->f_offset = uap->off;
41213878Ssam 		break;
41313878Ssam 
41413878Ssam 	default:
41513878Ssam 		u.u_error = EINVAL;
41613878Ssam 		return;
41713878Ssam 	}
41813878Ssam 	u.u_r.r_off = fp->f_offset;
4196254Sroot }
4206254Sroot 
4216254Sroot /*
4226254Sroot  * Access system call
4236254Sroot  */
4246254Sroot saccess()
4256254Sroot {
4266254Sroot 	register svuid, svgid;
4276254Sroot 	register struct inode *ip;
4286254Sroot 	register struct a {
4296254Sroot 		char	*fname;
4306254Sroot 		int	fmode;
43116694Smckusick 	} *uap = (struct a *)u.u_ap;
43216694Smckusick 	register struct nameidata *ndp = &u.u_nd;
4336254Sroot 
4346254Sroot 	svuid = u.u_uid;
4356254Sroot 	svgid = u.u_gid;
4366254Sroot 	u.u_uid = u.u_ruid;
4376254Sroot 	u.u_gid = u.u_rgid;
43816694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
43916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
44016694Smckusick 	ndp->ni_dirp = uap->fname;
44116694Smckusick 	ip = namei(ndp);
4426254Sroot 	if (ip != NULL) {
44312756Ssam 		if ((uap->fmode&R_OK) && access(ip, IREAD))
4447701Ssam 			goto done;
44512756Ssam 		if ((uap->fmode&W_OK) && access(ip, IWRITE))
4467701Ssam 			goto done;
44712756Ssam 		if ((uap->fmode&X_OK) && access(ip, IEXEC))
4487701Ssam 			goto done;
4497701Ssam done:
4506254Sroot 		iput(ip);
4516254Sroot 	}
4526254Sroot 	u.u_uid = svuid;
4536254Sroot 	u.u_gid = svgid;
4546254Sroot }
4556254Sroot 
4566254Sroot /*
4576574Smckusic  * Stat system call.  This version follows links.
45837Sbill  */
45937Sbill stat()
46037Sbill {
46137Sbill 
46216694Smckusick 	stat1(FOLLOW);
46337Sbill }
46437Sbill 
46537Sbill /*
4666574Smckusic  * Lstat system call.  This version does not follow links.
4675992Swnj  */
4685992Swnj lstat()
4695992Swnj {
47012756Ssam 
47116694Smckusick 	stat1(NOFOLLOW);
47212756Ssam }
47312756Ssam 
47412756Ssam stat1(follow)
47512756Ssam 	int follow;
47612756Ssam {
4775992Swnj 	register struct inode *ip;
4785992Swnj 	register struct a {
4795992Swnj 		char	*fname;
48012756Ssam 		struct stat *ub;
48116694Smckusick 	} *uap = (struct a *)u.u_ap;
48212756Ssam 	struct stat sb;
48316694Smckusick 	register struct nameidata *ndp = &u.u_nd;
4845992Swnj 
48516694Smckusick 	ndp->ni_nameiop = LOOKUP | follow;
48616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
48716694Smckusick 	ndp->ni_dirp = uap->fname;
48816694Smckusick 	ip = namei(ndp);
4895992Swnj 	if (ip == NULL)
4905992Swnj 		return;
49113043Ssam 	(void) ino_stat(ip, &sb);
4925992Swnj 	iput(ip);
49312756Ssam 	u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
4945992Swnj }
4955992Swnj 
4965992Swnj /*
4975992Swnj  * Return target name of a symbolic link
49837Sbill  */
4995992Swnj readlink()
5005992Swnj {
5015992Swnj 	register struct inode *ip;
5025992Swnj 	register struct a {
5035992Swnj 		char	*name;
5045992Swnj 		char	*buf;
5055992Swnj 		int	count;
5067826Sroot 	} *uap = (struct a *)u.u_ap;
50716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
5087826Sroot 	int resid;
5095992Swnj 
51016694Smckusick 	ndp->ni_nameiop = LOOKUP;
51116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
51216694Smckusick 	ndp->ni_dirp = uap->name;
51316694Smckusick 	ip = namei(ndp);
5145992Swnj 	if (ip == NULL)
5155992Swnj 		return;
5165992Swnj 	if ((ip->i_mode&IFMT) != IFLNK) {
51721015Smckusick 		u.u_error = EINVAL;
5185992Swnj 		goto out;
5195992Swnj 	}
52026361Skarels 	u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, (off_t)0, 0,
52126361Skarels 	    &resid);
5225992Swnj out:
5235992Swnj 	iput(ip);
5247826Sroot 	u.u_r.r_val1 = uap->count - resid;
5255992Swnj }
5265992Swnj 
5279167Ssam /*
5289167Ssam  * Change mode of a file given path name.
5299167Ssam  */
5306254Sroot chmod()
5315992Swnj {
5327701Ssam 	struct inode *ip;
5337701Ssam 	struct a {
5346254Sroot 		char	*fname;
5356254Sroot 		int	fmode;
53616694Smckusick 	} *uap = (struct a *)u.u_ap;
5375992Swnj 
53816694Smckusick 	if ((ip = owner(uap->fname, FOLLOW)) == NULL)
5395992Swnj 		return;
54021015Smckusick 	u.u_error = chmod1(ip, uap->fmode);
5419167Ssam 	iput(ip);
5427701Ssam }
5437439Sroot 
5449167Ssam /*
5459167Ssam  * Change mode of a file given a file descriptor.
5469167Ssam  */
5477701Ssam fchmod()
5487701Ssam {
5497701Ssam 	struct a {
5507701Ssam 		int	fd;
5517701Ssam 		int	fmode;
55216694Smckusick 	} *uap = (struct a *)u.u_ap;
5537701Ssam 	register struct inode *ip;
5547701Ssam 	register struct file *fp;
5557701Ssam 
55612756Ssam 	fp = getinode(uap->fd);
5577701Ssam 	if (fp == NULL)
5587701Ssam 		return;
55912756Ssam 	ip = (struct inode *)fp->f_data;
5609167Ssam 	if (u.u_uid != ip->i_uid && !suser())
5619167Ssam 		return;
56216664Smckusick 	ILOCK(ip);
56321015Smckusick 	u.u_error = chmod1(ip, uap->fmode);
56416664Smckusick 	IUNLOCK(ip);
5657701Ssam }
5667701Ssam 
5679167Ssam /*
5689167Ssam  * Change the mode on a file.
5699167Ssam  * Inode must be locked before calling.
5709167Ssam  */
5717701Ssam chmod1(ip, mode)
5727701Ssam 	register struct inode *ip;
5737701Ssam 	register int mode;
5747701Ssam {
5757868Sroot 
57621015Smckusick 	if (ip->i_fs->fs_ronly)
57721015Smckusick 		return (EROFS);
5786254Sroot 	ip->i_mode &= ~07777;
5797439Sroot 	if (u.u_uid) {
58021015Smckusick 		if ((ip->i_mode & IFMT) != IFDIR)
58121015Smckusick 			mode &= ~ISVTX;
58211811Ssam 		if (!groupmember(ip->i_gid))
58311811Ssam 			mode &= ~ISGID;
5847439Sroot 	}
5857701Ssam 	ip->i_mode |= mode&07777;
5866254Sroot 	ip->i_flag |= ICHG;
5876254Sroot 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
5886254Sroot 		xrele(ip);
58921015Smckusick 	return (0);
5905992Swnj }
5915992Swnj 
5929167Ssam /*
5939167Ssam  * Set ownership given a path name.
5949167Ssam  */
5956254Sroot chown()
59637Sbill {
5977701Ssam 	struct inode *ip;
5987701Ssam 	struct a {
5996254Sroot 		char	*fname;
6006254Sroot 		int	uid;
6016254Sroot 		int	gid;
60216694Smckusick 	} *uap = (struct a *)u.u_ap;
603*36614Sbostic 	register struct nameidata *ndp = &u.u_nd;
60437Sbill 
605*36614Sbostic 	ndp->ni_nameiop = LOOKUP | NOFOLLOW;
606*36614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
607*36614Sbostic 	ndp->ni_dirp = uap->fname;
608*36614Sbostic 	ip = namei(ndp);
609*36614Sbostic 	if (ip == NULL)
61037Sbill 		return;
61111811Ssam 	u.u_error = chown1(ip, uap->uid, uap->gid);
6129167Ssam 	iput(ip);
6137701Ssam }
6147439Sroot 
6159167Ssam /*
6169167Ssam  * Set ownership given a file descriptor.
6179167Ssam  */
6187701Ssam fchown()
6197701Ssam {
6207701Ssam 	struct a {
6217701Ssam 		int	fd;
6227701Ssam 		int	uid;
6237701Ssam 		int	gid;
62416694Smckusick 	} *uap = (struct a *)u.u_ap;
6257701Ssam 	register struct inode *ip;
6267701Ssam 	register struct file *fp;
6277701Ssam 
62812756Ssam 	fp = getinode(uap->fd);
6297701Ssam 	if (fp == NULL)
6307701Ssam 		return;
63112756Ssam 	ip = (struct inode *)fp->f_data;
63216664Smckusick 	ILOCK(ip);
63311811Ssam 	u.u_error = chown1(ip, uap->uid, uap->gid);
63416664Smckusick 	IUNLOCK(ip);
6357701Ssam }
6367701Ssam 
6377701Ssam /*
6387701Ssam  * Perform chown operation on inode ip;
6397701Ssam  * inode must be locked prior to call.
6407701Ssam  */
6417701Ssam chown1(ip, uid, gid)
6427701Ssam 	register struct inode *ip;
6437701Ssam 	int uid, gid;
6447701Ssam {
6457701Ssam #ifdef QUOTA
6467701Ssam 	register long change;
64711811Ssam #endif
6487701Ssam 
64921015Smckusick 	if (ip->i_fs->fs_ronly)
65021015Smckusick 		return (EROFS);
65111811Ssam 	if (uid == -1)
65211811Ssam 		uid = ip->i_uid;
65311811Ssam 	if (gid == -1)
65411811Ssam 		gid = ip->i_gid;
655*36614Sbostic 	/*
656*36614Sbostic 	 * If we don't own the file, are trying to change the owner
657*36614Sbostic 	 * of the file, or are not a member of the target group,
658*36614Sbostic 	 * the caller must be superuser or the call fails.
659*36614Sbostic 	 */
660*36614Sbostic 	if ((u.u_uid != ip->i_uid || uid != ip->i_uid ||
661*36614Sbostic 	    !groupmember((gid_t)gid)) && !suser())
66226473Skarels 		return (u.u_error);
66311811Ssam #ifdef QUOTA
66414385Ssam 	if (ip->i_uid == uid)		/* this just speeds things a little */
6657482Skre 		change = 0;
66612646Ssam 	else
66712646Ssam 		change = ip->i_blocks;
66812646Ssam 	(void) chkdq(ip, -change, 1);
66912646Ssam 	(void) chkiq(ip->i_dev, ip, ip->i_uid, 1);
6707482Skre 	dqrele(ip->i_dquot);
6717482Skre #endif
67211811Ssam 	ip->i_uid = uid;
67311811Ssam 	ip->i_gid = gid;
6746254Sroot 	ip->i_flag |= ICHG;
6756254Sroot 	if (u.u_ruid != 0)
6766254Sroot 		ip->i_mode &= ~(ISUID|ISGID);
6777701Ssam #ifdef QUOTA
6787482Skre 	ip->i_dquot = inoquota(ip);
67912646Ssam 	(void) chkdq(ip, change, 1);
68026361Skarels 	(void) chkiq(ip->i_dev, (struct inode *)NULL, (uid_t)uid, 1);
68112646Ssam 	return (u.u_error);		/* should == 0 ALWAYS !! */
68212646Ssam #else
68312646Ssam 	return (0);
6847482Skre #endif
68537Sbill }
68637Sbill 
68711811Ssam utimes()
68811811Ssam {
68911811Ssam 	register struct a {
69011811Ssam 		char	*fname;
69111811Ssam 		struct	timeval *tptr;
69211811Ssam 	} *uap = (struct a *)u.u_ap;
69311811Ssam 	register struct inode *ip;
69411811Ssam 	struct timeval tv[2];
69511811Ssam 
69616694Smckusick 	if ((ip = owner(uap->fname, FOLLOW)) == NULL)
69711811Ssam 		return;
69821015Smckusick 	if (ip->i_fs->fs_ronly) {
69921015Smckusick 		u.u_error = EROFS;
70021015Smckusick 		iput(ip);
70121015Smckusick 		return;
70221015Smckusick 	}
70311811Ssam 	u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
70411811Ssam 	if (u.u_error == 0) {
70511811Ssam 		ip->i_flag |= IACC|IUPD|ICHG;
70611811Ssam 		iupdat(ip, &tv[0], &tv[1], 0);
70711811Ssam 	}
70811811Ssam 	iput(ip);
70911811Ssam }
71011811Ssam 
7119167Ssam /*
7129167Ssam  * Flush any pending I/O.
7139167Ssam  */
7146254Sroot sync()
71537Sbill {
71637Sbill 
7178673Sroot 	update();
71837Sbill }
7197535Sroot 
7209167Ssam /*
7219167Ssam  * Truncate a file given its path name.
7229167Ssam  */
7237701Ssam truncate()
7247701Ssam {
7257701Ssam 	struct a {
7267701Ssam 		char	*fname;
72726473Skarels 		off_t	length;
7287826Sroot 	} *uap = (struct a *)u.u_ap;
7297701Ssam 	struct inode *ip;
73016694Smckusick 	register struct nameidata *ndp = &u.u_nd;
7317701Ssam 
73216694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
73316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
73416694Smckusick 	ndp->ni_dirp = uap->fname;
73516694Smckusick 	ip = namei(ndp);
7367701Ssam 	if (ip == NULL)
7377701Ssam 		return;
7387701Ssam 	if (access(ip, IWRITE))
7397701Ssam 		goto bad;
7407701Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
7417701Ssam 		u.u_error = EISDIR;
7427701Ssam 		goto bad;
7437701Ssam 	}
74426473Skarels 	itrunc(ip, (u_long)uap->length);
7457701Ssam bad:
7467701Ssam 	iput(ip);
7477701Ssam }
7487701Ssam 
7499167Ssam /*
7509167Ssam  * Truncate a file given a file descriptor.
7519167Ssam  */
7527701Ssam ftruncate()
7537701Ssam {
7547701Ssam 	struct a {
7557701Ssam 		int	fd;
75626473Skarels 		off_t	length;
7577826Sroot 	} *uap = (struct a *)u.u_ap;
7587701Ssam 	struct inode *ip;
7597701Ssam 	struct file *fp;
7607701Ssam 
76112756Ssam 	fp = getinode(uap->fd);
7627701Ssam 	if (fp == NULL)
7637701Ssam 		return;
7647701Ssam 	if ((fp->f_flag&FWRITE) == 0) {
7657701Ssam 		u.u_error = EINVAL;
7667701Ssam 		return;
7677701Ssam 	}
76812756Ssam 	ip = (struct inode *)fp->f_data;
76916664Smckusick 	ILOCK(ip);
77026473Skarels 	itrunc(ip, (u_long)uap->length);
77116664Smckusick 	IUNLOCK(ip);
7727701Ssam }
7737701Ssam 
7749167Ssam /*
7759167Ssam  * Synch an open file.
7769167Ssam  */
7779167Ssam fsync()
7789167Ssam {
7799167Ssam 	struct a {
7809167Ssam 		int	fd;
7819167Ssam 	} *uap = (struct a *)u.u_ap;
7829167Ssam 	struct inode *ip;
7839167Ssam 	struct file *fp;
7849167Ssam 
78512756Ssam 	fp = getinode(uap->fd);
7869167Ssam 	if (fp == NULL)
7879167Ssam 		return;
78812756Ssam 	ip = (struct inode *)fp->f_data;
78916664Smckusick 	ILOCK(ip);
79030598Smckusick 	if (fp->f_flag&FWRITE)
79130598Smckusick 		ip->i_flag |= ICHG;
7929167Ssam 	syncip(ip);
79316664Smckusick 	IUNLOCK(ip);
7949167Ssam }
7959167Ssam 
7969167Ssam /*
7979167Ssam  * Rename system call.
7989167Ssam  * 	rename("foo", "bar");
7999167Ssam  * is essentially
8009167Ssam  *	unlink("bar");
8019167Ssam  *	link("foo", "bar");
8029167Ssam  *	unlink("foo");
8039167Ssam  * but ``atomically''.  Can't do full commit without saving state in the
8049167Ssam  * inode on disk which isn't feasible at this time.  Best we can do is
8059167Ssam  * always guarantee the target exists.
8069167Ssam  *
8079167Ssam  * Basic algorithm is:
8089167Ssam  *
8099167Ssam  * 1) Bump link count on source while we're linking it to the
8109167Ssam  *    target.  This also insure the inode won't be deleted out
81116776Smckusick  *    from underneath us while we work (it may be truncated by
81216776Smckusick  *    a concurrent `trunc' or `open' for creation).
8139167Ssam  * 2) Link source to destination.  If destination already exists,
8149167Ssam  *    delete it first.
81516776Smckusick  * 3) Unlink source reference to inode if still around. If a
81616776Smckusick  *    directory was moved and the parent of the destination
8179167Ssam  *    is different from the source, patch the ".." entry in the
8189167Ssam  *    directory.
8199167Ssam  *
8209167Ssam  * Source and destination must either both be directories, or both
8219167Ssam  * not be directories.  If target is a directory, it must be empty.
8229167Ssam  */
8237701Ssam rename()
8247701Ssam {
8257701Ssam 	struct a {
8267701Ssam 		char	*from;
8277701Ssam 		char	*to;
82816694Smckusick 	} *uap = (struct a *)u.u_ap;
8299167Ssam 	register struct inode *ip, *xp, *dp;
83016776Smckusick 	struct dirtemplate dirbuf;
83116776Smckusick 	int doingdirectory = 0, oldparent = 0, newparent = 0;
83216694Smckusick 	register struct nameidata *ndp = &u.u_nd;
83310051Ssam 	int error = 0;
8347701Ssam 
83516694Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT;
83616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
83716694Smckusick 	ndp->ni_dirp = uap->from;
83816694Smckusick 	ip = namei(ndp);
8399167Ssam 	if (ip == NULL)
8409167Ssam 		return;
84116694Smckusick 	dp = ndp->ni_pdir;
8429167Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
8439167Ssam 		register struct direct *d;
8449167Ssam 
84516694Smckusick 		d = &ndp->ni_dent;
8469167Ssam 		/*
84711641Ssam 		 * Avoid ".", "..", and aliases of "." for obvious reasons.
8489167Ssam 		 */
84911641Ssam 		if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
85011641Ssam 		    (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
85116776Smckusick 		    (dp == ip) || (ip->i_flag & IRENAME)) {
85211641Ssam 			iput(dp);
85311641Ssam 			if (dp == ip)
85411641Ssam 				irele(ip);
85511641Ssam 			else
85610051Ssam 				iput(ip);
85711641Ssam 			u.u_error = EINVAL;
85811641Ssam 			return;
8599167Ssam 		}
86016776Smckusick 		ip->i_flag |= IRENAME;
8619167Ssam 		oldparent = dp->i_number;
8629167Ssam 		doingdirectory++;
8639167Ssam 	}
86411641Ssam 	iput(dp);
8659167Ssam 
8669167Ssam 	/*
8679167Ssam 	 * 1) Bump link count while we're moving stuff
8689167Ssam 	 *    around.  If we crash somewhere before
8699167Ssam 	 *    completing our work, the link count
8709167Ssam 	 *    may be wrong, but correctable.
8719167Ssam 	 */
8729167Ssam 	ip->i_nlink++;
8739167Ssam 	ip->i_flag |= ICHG;
8749167Ssam 	iupdat(ip, &time, &time, 1);
87516664Smckusick 	IUNLOCK(ip);
8769167Ssam 
8779167Ssam 	/*
8789167Ssam 	 * When the target exists, both the directory
8799167Ssam 	 * and target inodes are returned locked.
8809167Ssam 	 */
88116694Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE;
88216694Smckusick 	ndp->ni_dirp = (caddr_t)uap->to;
88316694Smckusick 	xp = namei(ndp);
88410051Ssam 	if (u.u_error) {
88510051Ssam 		error = u.u_error;
8869167Ssam 		goto out;
88710051Ssam 	}
88816694Smckusick 	dp = ndp->ni_pdir;
8899167Ssam 	/*
89011641Ssam 	 * If ".." must be changed (ie the directory gets a new
89112816Smckusick 	 * parent) then the source directory must not be in the
89212816Smckusick 	 * directory heirarchy above the target, as this would
89312816Smckusick 	 * orphan everything below the source directory. Also
89412816Smckusick 	 * the user must have write permission in the source so
89512816Smckusick 	 * as to be able to change "..". We must repeat the call
89612816Smckusick 	 * to namei, as the parent directory is unlocked by the
89712816Smckusick 	 * call to checkpath().
89811641Ssam 	 */
89916776Smckusick 	if (oldparent != dp->i_number)
90016776Smckusick 		newparent = dp->i_number;
90116776Smckusick 	if (doingdirectory && newparent) {
90212816Smckusick 		if (access(ip, IWRITE))
90312816Smckusick 			goto bad;
90412816Smckusick 		do {
90516694Smckusick 			dp = ndp->ni_pdir;
90612816Smckusick 			if (xp != NULL)
90712816Smckusick 				iput(xp);
90812816Smckusick 			u.u_error = checkpath(ip, dp);
90912816Smckusick 			if (u.u_error)
91012816Smckusick 				goto out;
91116694Smckusick 			xp = namei(ndp);
91212816Smckusick 			if (u.u_error) {
91312816Smckusick 				error = u.u_error;
91412816Smckusick 				goto out;
91512816Smckusick 			}
91616694Smckusick 		} while (dp != ndp->ni_pdir);
91712816Smckusick 	}
91811641Ssam 	/*
9199167Ssam 	 * 2) If target doesn't exist, link the target
9209167Ssam 	 *    to the source and unlink the source.
9219167Ssam 	 *    Otherwise, rewrite the target directory
9229167Ssam 	 *    entry to reference the source inode and
9239167Ssam 	 *    expunge the original entry's existence.
9249167Ssam 	 */
9259167Ssam 	if (xp == NULL) {
9269167Ssam 		if (dp->i_dev != ip->i_dev) {
92710051Ssam 			error = EXDEV;
9289167Ssam 			goto bad;
9299167Ssam 		}
9309167Ssam 		/*
93116776Smckusick 		 * Account for ".." in new directory.
93216776Smckusick 		 * When source and destination have the same
93316776Smckusick 		 * parent we don't fool with the link count.
9349167Ssam 		 */
93516776Smckusick 		if (doingdirectory && newparent) {
9369167Ssam 			dp->i_nlink++;
9379167Ssam 			dp->i_flag |= ICHG;
9389167Ssam 			iupdat(dp, &time, &time, 1);
9399167Ssam 		}
94016694Smckusick 		error = direnter(ip, ndp);
94110850Ssam 		if (error)
9429167Ssam 			goto out;
9439167Ssam 	} else {
9449167Ssam 		if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
94510051Ssam 			error = EXDEV;
9469167Ssam 			goto bad;
9479167Ssam 		}
9489167Ssam 		/*
94910590Ssam 		 * Short circuit rename(foo, foo).
95010590Ssam 		 */
95110590Ssam 		if (xp->i_number == ip->i_number)
95210590Ssam 			goto bad;
95310590Ssam 		/*
95424433Sbloom 		 * If the parent directory is "sticky", then the user must
95524433Sbloom 		 * own the parent directory, or the destination of the rename,
95624433Sbloom 		 * otherwise the destination may not be changed (except by
95724433Sbloom 		 * root). This implements append-only directories.
95824433Sbloom 		 */
95924433Sbloom 		if ((dp->i_mode & ISVTX) && u.u_uid != 0 &&
96024433Sbloom 		    u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) {
96124433Sbloom 			error = EPERM;
96224433Sbloom 			goto bad;
96324433Sbloom 		}
96424433Sbloom 		/*
96510051Ssam 		 * Target must be empty if a directory
96610051Ssam 		 * and have no links to it.
9679167Ssam 		 * Also, insure source and target are
9689167Ssam 		 * compatible (both directories, or both
9699167Ssam 		 * not directories).
9709167Ssam 		 */
9719167Ssam 		if ((xp->i_mode&IFMT) == IFDIR) {
97216776Smckusick 			if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) {
97310051Ssam 				error = ENOTEMPTY;
9749167Ssam 				goto bad;
9759167Ssam 			}
9769167Ssam 			if (!doingdirectory) {
97710051Ssam 				error = ENOTDIR;
9789167Ssam 				goto bad;
9799167Ssam 			}
98016776Smckusick 			cacheinval(dp);
9819167Ssam 		} else if (doingdirectory) {
98210051Ssam 			error = EISDIR;
9839167Ssam 			goto bad;
9849167Ssam 		}
98516694Smckusick 		dirrewrite(dp, ip, ndp);
98610051Ssam 		if (u.u_error) {
98710051Ssam 			error = u.u_error;
9889167Ssam 			goto bad1;
98910051Ssam 		}
9909167Ssam 		/*
99110051Ssam 		 * Adjust the link count of the target to
99210051Ssam 		 * reflect the dirrewrite above.  If this is
99310051Ssam 		 * a directory it is empty and there are
99410051Ssam 		 * no links to it, so we can squash the inode and
99510051Ssam 		 * any space associated with it.  We disallowed
99610051Ssam 		 * renaming over top of a directory with links to
99716776Smckusick 		 * it above, as the remaining link would point to
99816776Smckusick 		 * a directory without "." or ".." entries.
9999167Ssam 		 */
100010051Ssam 		xp->i_nlink--;
10019167Ssam 		if (doingdirectory) {
100210051Ssam 			if (--xp->i_nlink != 0)
100310051Ssam 				panic("rename: linked directory");
10049167Ssam 			itrunc(xp, (u_long)0);
100510051Ssam 		}
10069167Ssam 		xp->i_flag |= ICHG;
10079167Ssam 		iput(xp);
100810246Ssam 		xp = NULL;
10099167Ssam 	}
10109167Ssam 
10119167Ssam 	/*
10129167Ssam 	 * 3) Unlink the source.
10139167Ssam 	 */
101416694Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT;
101516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
101616694Smckusick 	ndp->ni_dirp = uap->from;
101716776Smckusick 	xp = namei(ndp);
101817758Smckusick 	if (xp != NULL)
101917758Smckusick 		dp = ndp->ni_pdir;
102017758Smckusick 	else
102117758Smckusick 		dp = NULL;
10229167Ssam 	/*
102316776Smckusick 	 * Insure that the directory entry still exists and has not
102416776Smckusick 	 * changed while the new name has been entered. If the source is
102516776Smckusick 	 * a file then the entry may have been unlinked or renamed. In
102616776Smckusick 	 * either case there is no further work to be done. If the source
102716776Smckusick 	 * is a directory then it cannot have been rmdir'ed; its link
102816776Smckusick 	 * count of three would cause a rmdir to fail with ENOTEMPTY.
102916776Smckusick 	 * The IRENAME flag insures that it cannot be moved by another
103016776Smckusick 	 * rename.
10319167Ssam 	 */
103217758Smckusick 	if (xp != ip) {
103316776Smckusick 		if (doingdirectory)
103417758Smckusick 			panic("rename: lost dir entry");
103516776Smckusick 	} else {
10369167Ssam 		/*
103716776Smckusick 		 * If the source is a directory with a
103816776Smckusick 		 * new parent, the link count of the old
103916776Smckusick 		 * parent directory must be decremented
104016776Smckusick 		 * and ".." set to point to the new parent.
10419167Ssam 		 */
104216776Smckusick 		if (doingdirectory && newparent) {
10439167Ssam 			dp->i_nlink--;
10449167Ssam 			dp->i_flag |= ICHG;
104516776Smckusick 			error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
104616776Smckusick 				sizeof (struct dirtemplate), (off_t)0, 1,
104716776Smckusick 				(int *)0);
104816776Smckusick 			if (error == 0) {
104916776Smckusick 				if (dirbuf.dotdot_namlen != 2 ||
105016776Smckusick 				    dirbuf.dotdot_name[0] != '.' ||
105116776Smckusick 				    dirbuf.dotdot_name[1] != '.') {
105216776Smckusick 					printf("rename: mangled dir\n");
105316776Smckusick 				} else {
105416776Smckusick 					dirbuf.dotdot_ino = newparent;
105516776Smckusick 					(void) rdwri(UIO_WRITE, xp,
105616776Smckusick 					    (caddr_t)&dirbuf,
105716776Smckusick 					    sizeof (struct dirtemplate),
105816776Smckusick 					    (off_t)0, 1, (int *)0);
105916776Smckusick 					cacheinval(dp);
106016776Smckusick 				}
106116776Smckusick 			}
10629167Ssam 		}
106316694Smckusick 		if (dirremove(ndp)) {
106416776Smckusick 			xp->i_nlink--;
106516776Smckusick 			xp->i_flag |= ICHG;
10669167Ssam 		}
106716776Smckusick 		xp->i_flag &= ~IRENAME;
106816776Smckusick 		if (error == 0)		/* XXX conservative */
106910051Ssam 			error = u.u_error;
10709167Ssam 	}
10719167Ssam 	if (dp)
10729167Ssam 		iput(dp);
107316776Smckusick 	if (xp)
107416776Smckusick 		iput(xp);
107516776Smckusick 	irele(ip);
107616776Smckusick 	if (error)
107716776Smckusick 		u.u_error = error;
107816776Smckusick 	return;
10799167Ssam 
10809167Ssam bad:
108110246Ssam 	iput(dp);
10829167Ssam bad1:
10839167Ssam 	if (xp)
108410246Ssam 		iput(xp);
10859167Ssam out:
10869167Ssam 	ip->i_nlink--;
10879167Ssam 	ip->i_flag |= ICHG;
10889167Ssam 	irele(ip);
108910051Ssam 	if (error)
109010051Ssam 		u.u_error = error;
10917701Ssam }
10927701Ssam 
10937535Sroot /*
10947535Sroot  * Make a new file.
10957535Sroot  */
10967535Sroot struct inode *
109716694Smckusick maknode(mode, ndp)
10987535Sroot 	int mode;
109916694Smckusick 	register struct nameidata *ndp;
11007535Sroot {
11017535Sroot 	register struct inode *ip;
110216694Smckusick 	register struct inode *pdir = ndp->ni_pdir;
11037535Sroot 	ino_t ipref;
11047535Sroot 
11057535Sroot 	if ((mode & IFMT) == IFDIR)
110616694Smckusick 		ipref = dirpref(pdir->i_fs);
11077535Sroot 	else
110816694Smckusick 		ipref = pdir->i_number;
110916694Smckusick 	ip = ialloc(pdir, ipref, mode);
11107535Sroot 	if (ip == NULL) {
111116694Smckusick 		iput(pdir);
11127701Ssam 		return (NULL);
11137535Sroot 	}
11147701Ssam #ifdef QUOTA
11157535Sroot 	if (ip->i_dquot != NODQUOT)
11167535Sroot 		panic("maknode: dquot");
11177535Sroot #endif
11187535Sroot 	ip->i_flag |= IACC|IUPD|ICHG;
11197535Sroot 	if ((mode & IFMT) == 0)
11207535Sroot 		mode |= IFREG;
11217535Sroot 	ip->i_mode = mode & ~u.u_cmask;
11227535Sroot 	ip->i_nlink = 1;
11237535Sroot 	ip->i_uid = u.u_uid;
112416694Smckusick 	ip->i_gid = pdir->i_gid;
112530926Skarels 	if (ip->i_mode & ISGID && !groupmember(ip->i_gid) && !suser())
112611811Ssam 		ip->i_mode &= ~ISGID;
11277701Ssam #ifdef QUOTA
11287535Sroot 	ip->i_dquot = inoquota(ip);
11297535Sroot #endif
11307535Sroot 
11317535Sroot 	/*
11327535Sroot 	 * Make sure inode goes to disk before directory entry.
11337535Sroot 	 */
11348673Sroot 	iupdat(ip, &time, &time, 1);
113516694Smckusick 	u.u_error = direnter(ip, ndp);
11367535Sroot 	if (u.u_error) {
11377535Sroot 		/*
113810850Ssam 		 * Write error occurred trying to update directory
113910850Ssam 		 * so must deallocate the inode.
11407535Sroot 		 */
11417535Sroot 		ip->i_nlink = 0;
11427535Sroot 		ip->i_flag |= ICHG;
11437535Sroot 		iput(ip);
11447701Ssam 		return (NULL);
11457535Sroot 	}
11467701Ssam 	return (ip);
11477535Sroot }
114812756Ssam 
114912756Ssam /*
115012756Ssam  * A virgin directory (no blushing please).
115112756Ssam  */
115212756Ssam struct dirtemplate mastertemplate = {
115312756Ssam 	0, 12, 1, ".",
115412756Ssam 	0, DIRBLKSIZ - 12, 2, ".."
115512756Ssam };
115612756Ssam 
115712756Ssam /*
115812756Ssam  * Mkdir system call
115912756Ssam  */
116012756Ssam mkdir()
116112756Ssam {
116212756Ssam 	struct a {
116312756Ssam 		char	*name;
116412756Ssam 		int	dmode;
116516694Smckusick 	} *uap = (struct a *)u.u_ap;
116612756Ssam 	register struct inode *ip, *dp;
116712756Ssam 	struct dirtemplate dirtemplate;
116816694Smckusick 	register struct nameidata *ndp = &u.u_nd;
116912756Ssam 
117016694Smckusick 	ndp->ni_nameiop = CREATE;
117116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
117216694Smckusick 	ndp->ni_dirp = uap->name;
117316694Smckusick 	ip = namei(ndp);
117412756Ssam 	if (u.u_error)
117512756Ssam 		return;
117612756Ssam 	if (ip != NULL) {
117712756Ssam 		iput(ip);
117812756Ssam 		u.u_error = EEXIST;
117912756Ssam 		return;
118012756Ssam 	}
118116694Smckusick 	dp = ndp->ni_pdir;
118212756Ssam 	uap->dmode &= 0777;
118312756Ssam 	uap->dmode |= IFDIR;
118412756Ssam 	/*
118512756Ssam 	 * Must simulate part of maknode here
118612756Ssam 	 * in order to acquire the inode, but
118712756Ssam 	 * not have it entered in the parent
118812756Ssam 	 * directory.  The entry is made later
118912756Ssam 	 * after writing "." and ".." entries out.
119012756Ssam 	 */
119112756Ssam 	ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
119212756Ssam 	if (ip == NULL) {
119312756Ssam 		iput(dp);
119412756Ssam 		return;
119512756Ssam 	}
119612756Ssam #ifdef QUOTA
119712756Ssam 	if (ip->i_dquot != NODQUOT)
119812756Ssam 		panic("mkdir: dquot");
119912756Ssam #endif
120012756Ssam 	ip->i_flag |= IACC|IUPD|ICHG;
120112756Ssam 	ip->i_mode = uap->dmode & ~u.u_cmask;
120212756Ssam 	ip->i_nlink = 2;
120312756Ssam 	ip->i_uid = u.u_uid;
120412756Ssam 	ip->i_gid = dp->i_gid;
120512756Ssam #ifdef QUOTA
120612756Ssam 	ip->i_dquot = inoquota(ip);
120712756Ssam #endif
120812756Ssam 	iupdat(ip, &time, &time, 1);
120912756Ssam 
121012756Ssam 	/*
121112756Ssam 	 * Bump link count in parent directory
121212756Ssam 	 * to reflect work done below.  Should
121312756Ssam 	 * be done before reference is created
121412756Ssam 	 * so reparation is possible if we crash.
121512756Ssam 	 */
121612756Ssam 	dp->i_nlink++;
121712756Ssam 	dp->i_flag |= ICHG;
121812756Ssam 	iupdat(dp, &time, &time, 1);
121912756Ssam 
122012756Ssam 	/*
122112756Ssam 	 * Initialize directory with "."
122212756Ssam 	 * and ".." from static template.
122312756Ssam 	 */
122412756Ssam 	dirtemplate = mastertemplate;
122512756Ssam 	dirtemplate.dot_ino = ip->i_number;
122612756Ssam 	dirtemplate.dotdot_ino = dp->i_number;
122712756Ssam 	u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
122812756Ssam 		sizeof (dirtemplate), (off_t)0, 1, (int *)0);
122912756Ssam 	if (u.u_error) {
123012756Ssam 		dp->i_nlink--;
123112756Ssam 		dp->i_flag |= ICHG;
123212756Ssam 		goto bad;
123312756Ssam 	}
123418103Smckusick 	if (DIRBLKSIZ > ip->i_fs->fs_fsize)
123518103Smckusick 		panic("mkdir: blksize");     /* XXX - should grow with bmap() */
123618103Smckusick 	else
123718103Smckusick 		ip->i_size = DIRBLKSIZ;
123812756Ssam 	/*
123912756Ssam 	 * Directory all set up, now
124012756Ssam 	 * install the entry for it in
124112756Ssam 	 * the parent directory.
124212756Ssam 	 */
124316694Smckusick 	u.u_error = direnter(ip, ndp);
124412756Ssam 	dp = NULL;
124512756Ssam 	if (u.u_error) {
124616694Smckusick 		ndp->ni_nameiop = LOOKUP | NOCACHE;
124716694Smckusick 		ndp->ni_segflg = UIO_USERSPACE;
124816694Smckusick 		ndp->ni_dirp = uap->name;
124916694Smckusick 		dp = namei(ndp);
125012756Ssam 		if (dp) {
125112756Ssam 			dp->i_nlink--;
125212756Ssam 			dp->i_flag |= ICHG;
125312756Ssam 		}
125412756Ssam 	}
125512756Ssam bad:
125612756Ssam 	/*
125712756Ssam 	 * No need to do an explicit itrunc here,
125812756Ssam 	 * irele will do this for us because we set
125912756Ssam 	 * the link count to 0.
126012756Ssam 	 */
126112756Ssam 	if (u.u_error) {
126212756Ssam 		ip->i_nlink = 0;
126312756Ssam 		ip->i_flag |= ICHG;
126412756Ssam 	}
126512756Ssam 	if (dp)
126612756Ssam 		iput(dp);
126712756Ssam 	iput(ip);
126812756Ssam }
126912756Ssam 
127012756Ssam /*
127112756Ssam  * Rmdir system call.
127212756Ssam  */
127312756Ssam rmdir()
127412756Ssam {
127512756Ssam 	struct a {
127612756Ssam 		char	*name;
127716694Smckusick 	} *uap = (struct a *)u.u_ap;
127812756Ssam 	register struct inode *ip, *dp;
127916694Smckusick 	register struct nameidata *ndp = &u.u_nd;
128012756Ssam 
128116694Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT;
128216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
128316694Smckusick 	ndp->ni_dirp = uap->name;
128416694Smckusick 	ip = namei(ndp);
128512756Ssam 	if (ip == NULL)
128612756Ssam 		return;
128716694Smckusick 	dp = ndp->ni_pdir;
128812756Ssam 	/*
128912756Ssam 	 * No rmdir "." please.
129012756Ssam 	 */
129112756Ssam 	if (dp == ip) {
129212756Ssam 		irele(dp);
129312756Ssam 		iput(ip);
129412756Ssam 		u.u_error = EINVAL;
129512756Ssam 		return;
129612756Ssam 	}
129712756Ssam 	if ((ip->i_mode&IFMT) != IFDIR) {
129812756Ssam 		u.u_error = ENOTDIR;
129912756Ssam 		goto out;
130012756Ssam 	}
130112756Ssam 	/*
130212756Ssam 	 * Don't remove a mounted on directory.
130312756Ssam 	 */
130412756Ssam 	if (ip->i_dev != dp->i_dev) {
130512756Ssam 		u.u_error = EBUSY;
130612756Ssam 		goto out;
130712756Ssam 	}
130812756Ssam 	/*
130912756Ssam 	 * Verify the directory is empty (and valid).
131012756Ssam 	 * (Rmdir ".." won't be valid since
131112756Ssam 	 *  ".." will contain a reference to
131212756Ssam 	 *  the current directory and thus be
131312756Ssam 	 *  non-empty.)
131412756Ssam 	 */
131516776Smckusick 	if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) {
131612756Ssam 		u.u_error = ENOTEMPTY;
131712756Ssam 		goto out;
131812756Ssam 	}
131912756Ssam 	/*
132012756Ssam 	 * Delete reference to directory before purging
132112756Ssam 	 * inode.  If we crash in between, the directory
132212756Ssam 	 * will be reattached to lost+found,
132312756Ssam 	 */
132416694Smckusick 	if (dirremove(ndp) == 0)
132512756Ssam 		goto out;
132612756Ssam 	dp->i_nlink--;
132712756Ssam 	dp->i_flag |= ICHG;
132816776Smckusick 	cacheinval(dp);
132912756Ssam 	iput(dp);
133012756Ssam 	dp = NULL;
133112756Ssam 	/*
133212756Ssam 	 * Truncate inode.  The only stuff left
133312756Ssam 	 * in the directory is "." and "..".  The
133412756Ssam 	 * "." reference is inconsequential since
133512756Ssam 	 * we're quashing it.  The ".." reference
133612756Ssam 	 * has already been adjusted above.  We've
133712756Ssam 	 * removed the "." reference and the reference
133812756Ssam 	 * in the parent directory, but there may be
133912756Ssam 	 * other hard links so decrement by 2 and
134012756Ssam 	 * worry about them later.
134112756Ssam 	 */
134212756Ssam 	ip->i_nlink -= 2;
134312756Ssam 	itrunc(ip, (u_long)0);
134416739Smckusick 	cacheinval(ip);
134512756Ssam out:
134612756Ssam 	if (dp)
134712756Ssam 		iput(dp);
134812756Ssam 	iput(ip);
134912756Ssam }
135012756Ssam 
135112756Ssam struct file *
135212756Ssam getinode(fdes)
135312756Ssam 	int fdes;
135412756Ssam {
135516540Ssam 	struct file *fp;
135612756Ssam 
135716540Ssam 	if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
135816540Ssam 		u.u_error = EBADF;
135916540Ssam 		return ((struct file *)0);
136016540Ssam 	}
136112756Ssam 	if (fp->f_type != DTYPE_INODE) {
136212756Ssam 		u.u_error = EINVAL;
136316540Ssam 		return ((struct file *)0);
136412756Ssam 	}
136512756Ssam 	return (fp);
136612756Ssam }
136712756Ssam 
136812756Ssam /*
136912756Ssam  * mode mask for creation of files
137012756Ssam  */
137112756Ssam umask()
137212756Ssam {
137312756Ssam 	register struct a {
137412756Ssam 		int	mask;
137516694Smckusick 	} *uap = (struct a *)u.u_ap;
137612756Ssam 
137712756Ssam 	u.u_r.r_val1 = u.u_cmask;
137812756Ssam 	u.u_cmask = uap->mask & 07777;
137912756Ssam }
1380