+#include "../h/inode.h"
+#include "../h/fs.h"
+#include "../h/buf.h"
+#include "../h/proc.h"
+#include "../h/quota.h"
+#include "../h/descrip.h"
+#include "../h/uio.h"
+#include "../h/socket.h"
+#include "../h/socketvar.h"
+
+chdir()
+{
+
+ chdirec(&u.u_cdir);
+}
+
+chroot()
+{
+
+ if (suser())
+ chdirec(&u.u_rdir);
+}
+
+chdirec(ipp)
+ register struct inode **ipp;
+{
+ register struct inode *ip;
+ struct a {
+ char *fname;
+ };
+
+ ip = namei(uchar, 0, 1);
+ if(ip == NULL)
+ return;
+ if((ip->i_mode&IFMT) != IFDIR) {
+ u.u_error = ENOTDIR;
+ goto bad;
+ }
+ if(access(ip, IEXEC))
+ goto bad;
+ iunlock(ip);
+ if (*ipp)
+ irele(*ipp);
+ *ipp = ip;
+ return;
+
+bad:
+ iput(ip);
+}
+
+/*
+ * Open system call.
+ */
+open()
+{
+ register struct inode *ip;
+ register struct a {
+ char *fname;
+ int flags;
+ int mode;
+ } *uap;
+ int checkpermissions = 1;
+
+ uap = (struct a *)u.u_ap;
+ if (uap->flags&FCREATE) {
+ ip = namei(uchar, 1, 1);
+ if (ip == NULL) {
+ if (u.u_error)
+ return;
+ ip = maknode(uap->mode&07777&(~ISVTX));
+ checkpermissions = 0;
+ uap->flags &= ~FTRUNCATE;
+ }
+ } else
+ ip = namei(uchar, 0, 1);
+ if (ip == NULL)
+ return;
+ open1(ip, ++uap->flags, checkpermissions);
+}
+
+#ifndef NOCOMPAT
+/*
+ * Creat system call.
+ */
+ocreat()
+{
+ register struct inode *ip;
+ register struct a {
+ char *fname;
+ int fmode;
+ } *uap;
+
+ uap = (struct a *)u.u_ap;
+ ip = namei(uchar, 1, 1);
+ if (ip == NULL) {
+ if (u.u_error)
+ return;
+ ip = maknode(uap->fmode&07777&(~ISVTX));
+ if (ip == NULL)
+ return;
+ open1(ip, FWRITE, 0);
+ } else
+ open1(ip, FWRITE|FTRUNCATE, 0);
+}
+#endif
+
+/*
+ * Common code for open and creat.
+ * Check permissions (if we haven't done so already),
+ * allocate an open file structure, and call
+ * the device open routine, if any.
+ */
+open1(ip, mode, checkpermissions)
+ register struct inode *ip;
+ register mode;
+{
+ register struct file *fp;
+ int i, flags;
+
+ if (checkpermissions) {
+ if (mode&FREAD)
+ if (access(ip, IREAD))
+ goto bad;
+ if (mode&FWRITE) {
+ if (access(ip, IWRITE))
+ goto bad;
+ if ((ip->i_mode&IFMT) == IFDIR) {
+ u.u_error = EISDIR;
+ goto bad;
+ }
+ }
+ }
+
+ /*
+ * Check locking on inode. Release "inode lock"
+ * while doing so in case we block inside flocki.
+ */
+ flags = 0;
+ if (mode&(FRDLOCK|FWRLOCK)) {
+ iunlock(ip);
+ flags = flocki(ip, 0, mode);
+ ilock(ip);
+ if (u.u_error)
+ goto bad;
+ }
+ if (mode&FTRUNCATE)
+ itrunc(ip, 0);
+ iunlock(ip);
+ if ((fp = falloc()) == NULL)
+ goto out;
+ fp->f_flag = mode & FMODES;
+ fp->f_type = DTYPE_FILE;
+ i = u.u_r.r_val1;
+ fp->f_inode = ip;
+ u.u_error = openi(ip, mode);
+ if (u.u_error == 0) {
+ u.u_pofile[i] = flags;
+ return;
+ }
+ u.u_ofile[i] = NULL;
+ fp->f_count--;
+out:
+ irele(ip);
+ return;
+bad:
+ iput(ip);
+}
+
+/*
+ * Mknod system call
+ */
+mknod()
+{
+ register struct inode *ip;
+ register struct a {
+ char *fname;
+ int fmode;
+ int dev;
+ } *uap;
+
+ uap = (struct a *)u.u_ap;
+ if (suser()) {
+ ip = namei(uchar, 1, 0);
+ if (ip != NULL) {
+ u.u_error = EEXIST;
+ goto out;
+ }
+ }
+ if (u.u_error)
+ return;
+ ip = maknode(uap->fmode);
+ if (ip == NULL)
+ return;
+ if (uap->dev) {
+ /*
+ * Want to be able to use this to make badblock
+ * inodes, so don't truncate the dev number.
+ */
+ ip->i_rdev = uap->dev;
+ ip->i_flag |= IACC|IUPD|ICHG;
+ }
+
+out:
+ iput(ip);
+}
+
+/*
+ * link system call
+ */
+link()
+{
+ register struct inode *ip, *xp;
+ register struct a {
+ char *target;
+ char *linkname;
+ } *uap;
+
+ uap = (struct a *)u.u_ap;
+ ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */
+ if (ip == NULL)
+ return;
+ if ((ip->i_mode&IFMT)==IFDIR && !suser()) {
+ iput(ip);
+ return;
+ }
+ ip->i_nlink++;
+ ip->i_flag |= ICHG;
+ iupdat(ip, time, time, 1);
+ iunlock(ip);
+ u.u_dirp = (caddr_t)uap->linkname;
+ xp = namei(uchar, 1, 0);
+ if (xp != NULL) {
+ u.u_error = EEXIST;
+ iput(xp);
+ goto out;
+ }
+ if (u.u_error)
+ goto out;
+ if (u.u_pdir->i_dev != ip->i_dev) {
+ iput(u.u_pdir);
+ u.u_error = EXDEV;
+ goto out;
+ }
+ direnter(ip);
+out:
+ if (u.u_error) {
+ ip->i_nlink--;
+ ip->i_flag |= ICHG;
+ }
+ irele(ip);
+}
+
+/*
+ * symlink -- make a symbolic link
+ */
+symlink()
+{
+ register struct a {
+ char *target;
+ char *linkname;
+ } *uap;
+ register struct inode *ip;
+ register char *tp;
+ register c, nc;
+
+ uap = (struct a *)u.u_ap;
+ tp = uap->target;
+ nc = 0;
+ while (c = fubyte(tp)) {
+ if (c < 0) {
+ u.u_error = EFAULT;
+ return;
+ }
+ tp++;
+ nc++;
+ }
+ u.u_dirp = uap->linkname;
+ ip = namei(uchar, 1, 0);
+ if (ip) {
+ iput(ip);
+ u.u_error = EEXIST;
+ return;
+ }
+ if (u.u_error)
+ return;
+ ip = maknode(IFLNK | 0777);
+ if (ip == NULL)
+ return;
+ u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0);
+ iput(ip);
+}
+
+/*
+ * Unlink system call.
+ * Hard to avoid races here, especially
+ * in unlinking directories.
+ */
+unlink()
+{
+ register struct inode *ip, *pp;
+ struct a {
+ char *fname;
+ };
+ int unlinkingdot = 0;
+
+ pp = namei(uchar, 2, 0);
+ if (pp == NULL)
+ return;
+
+ /*
+ * Check for unlink(".")
+ * to avoid hanging on the iget
+ */
+ if (pp->i_number == u.u_dent.d_ino) {
+ ip = pp;
+ ip->i_count++;
+ unlinkingdot++;
+ } else
+ ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
+ if(ip == NULL)
+ goto out1;
+ if((ip->i_mode&IFMT)==IFDIR && !suser())
+ goto out;
+ /*
+ * Don't unlink a mounted file.
+ */
+ if (ip->i_dev != pp->i_dev) {
+ u.u_error = EBUSY;
+ goto out;
+ }
+ if (ip->i_flag&ITEXT)
+ xrele(ip); /* try once to free text */
+ if (dirremove()) {
+ ip->i_nlink--;
+ ip->i_flag |= ICHG;
+ }
+out:
+ if (unlinkingdot)
+ irele(ip);
+ else
+ iput(ip);
+out1:
+ iput(pp);
+}
+
+/*
+ * Seek system call
+ */
+lseek()
+{
+ register struct file *fp;
+ register struct a {
+ int fd;
+ off_t off;
+ int sbase;
+ } *uap;
+
+ uap = (struct a *)u.u_ap;
+ fp = getf(uap->fd);
+ if (fp == NULL)
+ return;
+ if (fp->f_type == DTYPE_SOCKET) {
+ u.u_error = ESPIPE;
+ return;
+ }
+ if (uap->sbase == FSEEK_RELATIVE)
+ uap->off += fp->f_offset;
+ else if (uap->sbase == FSEEK_EOF)
+ uap->off += fp->f_inode->i_size;
+ fp->f_offset = uap->off;
+ u.u_r.r_off = uap->off;
+}
+
+/*
+ * Access system call
+ */
+saccess()
+{
+ register svuid, svgid;
+ register struct inode *ip;
+ register struct a {
+ char *fname;
+ int fmode;
+ } *uap;
+
+ uap = (struct a *)u.u_ap;
+ svuid = u.u_uid;
+ svgid = u.u_gid;
+ u.u_uid = u.u_ruid;
+ u.u_gid = u.u_rgid;
+ ip = namei(uchar, 0, 1);
+ if (ip != NULL) {
+ if (uap->fmode&FACCESS_READ && access(ip, IREAD))
+ goto done;
+ if (uap->fmode&FACCESS_WRITE && access(ip, IWRITE))
+ goto done;
+ if (uap->fmode&FACCESS_EXECUTE && access(ip, IEXEC))
+ goto done;
+done:
+ iput(ip);
+ }
+ u.u_uid = svuid;
+ u.u_gid = svgid;
+}