-/* vfs_syscalls.c 6.18 85/05/22 */
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ * @(#)vfs_syscalls.c 7.3 (Berkeley) %G%
+ */
#include "param.h"
#include "systm.h"
register struct inode *ip;
register struct file *fp;
register struct nameidata *ndp = &u.u_nd;
- int i;
+ int indx;
-#ifdef notdef
- if ((mode&(FREAD|FWRITE)) == 0) {
- u.u_error = EINVAL;
+ fp = falloc();
+ if (fp == NULL)
return;
- }
-#endif
+ indx = u.u_r.r_val1;
ndp->ni_segflg = UIO_USERSPACE;
ndp->ni_dirp = fname;
if (mode&FCREAT) {
ip = namei(ndp);
if (ip == NULL) {
if (u.u_error)
- return;
+ goto bad1;
ip = maknode(arg&07777&(~ISVTX), ndp);
if (ip == NULL)
- return;
+ goto bad1;
mode &= ~FTRUNC;
} else {
if (mode&FEXCL) {
u.u_error = EEXIST;
- iput(ip);
- return;
+ goto bad;
}
mode &= ~FCREAT;
}
ndp->ni_nameiop = LOOKUP | FOLLOW;
ip = namei(ndp);
if (ip == NULL)
- return;
+ goto bad1;
}
if ((ip->i_mode & IFMT) == IFSOCK) {
u.u_error = EOPNOTSUPP;
}
}
}
- fp = falloc();
- if (fp == NULL)
- goto bad;
if (mode&FTRUNC)
itrunc(ip, (u_long)0);
IUNLOCK(ip);
fp->f_type = DTYPE_INODE;
fp->f_ops = &inodeops;
fp->f_data = (caddr_t)ip;
- i = u.u_r.r_val1;
if (setjmp(&u.u_qsave)) {
if (u.u_error == 0)
u.u_error = EINTR;
- u.u_ofile[i] = NULL;
+ u.u_ofile[indx] = NULL;
closef(fp);
return;
}
u.u_error = openi(ip, mode);
if (u.u_error == 0)
return;
- u.u_ofile[i] = NULL;
- fp->f_count--;
- irele(ip);
- return;
+ ILOCK(ip);
bad:
iput(ip);
+bad1:
+ u.u_ofile[indx] = NULL;
+ fp->f_count--;
}
/*
ip = maknode(IFLNK | 0777, ndp);
if (ip == NULL)
return;
- u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0);
+ u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, (off_t)0, 0,
+ (int *)0);
/* handle u.u_error != 0 */
iput(ip);
}
u.u_error = EINVAL;
goto out;
}
- u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid);
+ u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, (off_t)0, 0,
+ &resid);
out:
iput(ip);
u.u_r.r_val1 = uap->count - resid;
int gid;
} *uap = (struct a *)u.u_ap;
- if (!suser() || (ip = owner(uap->fname, NOFOLLOW)) == NULL)
+ if ((ip = owner(uap->fname, NOFOLLOW)) == NULL)
return;
u.u_error = chown1(ip, uap->uid, uap->gid);
iput(ip);
if (fp == NULL)
return;
ip = (struct inode *)fp->f_data;
- if (!suser())
- return;
ILOCK(ip);
u.u_error = chown1(ip, uap->uid, uap->gid);
IUNLOCK(ip);
uid = ip->i_uid;
if (gid == -1)
gid = ip->i_gid;
+ if (uid != ip->i_uid && !suser())
+ return (u.u_error);
+ if (gid != ip->i_gid && !groupmember((gid_t)gid) && !suser())
+ return (u.u_error);
#ifdef QUOTA
if (ip->i_uid == uid) /* this just speeds things a little */
change = 0;
#ifdef QUOTA
ip->i_dquot = inoquota(ip);
(void) chkdq(ip, change, 1);
- (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
+ (void) chkiq(ip->i_dev, (struct inode *)NULL, (uid_t)uid, 1);
return (u.u_error); /* should == 0 ALWAYS !! */
#else
return (0);
{
struct a {
char *fname;
- u_long length;
+ off_t length;
} *uap = (struct a *)u.u_ap;
struct inode *ip;
register struct nameidata *ndp = &u.u_nd;
u.u_error = EISDIR;
goto bad;
}
- itrunc(ip, uap->length);
+ itrunc(ip, (u_long)uap->length);
bad:
iput(ip);
}
{
struct a {
int fd;
- u_long length;
+ off_t length;
} *uap = (struct a *)u.u_ap;
struct inode *ip;
struct file *fp;
}
ip = (struct inode *)fp->f_data;
ILOCK(ip);
- itrunc(ip, uap->length);
+ itrunc(ip, (u_long)uap->length);
IUNLOCK(ip);
}
return;
ip = (struct inode *)fp->f_data;
ILOCK(ip);
+ if (fp->f_flag&FWRITE)
+ ip->i_flag |= ICHG;
syncip(ip);
IUNLOCK(ip);
}
*/
if (xp->i_number == ip->i_number)
goto bad;
+ /*
+ * If the parent directory is "sticky", then the user must
+ * own the parent directory, or the destination of the rename,
+ * otherwise the destination may not be changed (except by
+ * root). This implements append-only directories.
+ */
+ if ((dp->i_mode & ISVTX) && u.u_uid != 0 &&
+ u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) {
+ error = EPERM;
+ goto bad;
+ }
/*
* Target must be empty if a directory
* and have no links to it.
ip->i_nlink = 1;
ip->i_uid = u.u_uid;
ip->i_gid = pdir->i_gid;
- if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
+ if (ip->i_mode & ISGID && !groupmember(ip->i_gid) && !suser())
ip->i_mode &= ~ISGID;
#ifdef QUOTA
ip->i_dquot = inoquota(ip);