-/* ffs_vnops.c 4.48 83/01/11 */
+/* ffs_vnops.c 4.56 83/05/21 */
#include "../h/param.h"
#include "../h/systm.h"
u.u_error = EXDEV;
goto out;
}
- direnter(ip);
+ u.u_error = direnter(ip);
out:
if (u.u_error) {
ip->i_nlink--;
ds.st_blksize = MAXBSIZE;
else
ds.st_blksize = ip->i_fs->fs_bsize;
- ds.st_spare4[0] = ds.st_spare4[1] = ds.st_spare4[2] = 0;
+ ds.st_blocks = ip->i_blocks;
+ ds.st_spare4[0] = ds.st_spare4[1] = 0;
u.u_error = copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds));
}
ip->i_mode &= ~07777;
if (u.u_uid) {
mode &= ~ISVTX;
- for (gp = u.u_groups; gp < &u.u_groups[NGROUPS]; gp++)
- if (*gp == ip->i_gid)
- goto ok;
- mode &= ~ISGID;
-ok:
- ;
-#ifdef MUSH
- if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 &&
- (ip->i_mode & IFMT) != IFCHR)
- mode &= ~u.u_cmask;
-#endif
+ if (!groupmember(ip->i_gid))
+ mode &= ~ISGID;
}
ip->i_mode |= mode&07777;
ip->i_flag |= ICHG;
uap = (struct a *)u.u_ap;
if (!suser() || (ip = owner(0)) == NULL)
return;
- chown1(ip, uap->uid, uap->gid);
+ u.u_error = chown1(ip, uap->uid, uap->gid);
iput(ip);
}
if (!suser())
return;
ilock(ip);
- chown1(ip, uap->uid, uap->gid);
+ u.u_error = chown1(ip, uap->uid, uap->gid);
iunlock(ip);
}
{
#ifdef QUOTA
register long change;
+#endif
- /*
- * This doesn't allow for holes in files (which hopefully don't
- * happen often in files that we chown), and is not accurate anyway
- * (eg: it totally ignores 3 level indir blk files - but hopefully
- * noone who can make a file that big will have a quota)
- */
- if (ip->i_uid == uid)
+ if (uid == -1)
+ uid = ip->i_uid;
+ if (gid == -1)
+ gid = ip->i_gid;
+#ifdef QUOTA
+ if (ip->i_uid != uid) /* this just speeds things a little */
change = 0;
- else {
- register struct fs *fs = ip->i_fs;
-
- if (ip->i_size > (change = NDADDR * fs->fs_bsize)) {
- register off_t size;
-
- size = blkroundup(fs, ip->i_size) - change;
- change += size;
- change += fs->fs_bsize;
- /* this assumes NIADDR <= 2 */
- if (size > NINDIR(fs) * fs->fs_bsize)
- change += fs->fs_bsize;
- } else
- change = fragroundup(fs, ip->i_size);
- change /= DEV_BSIZE;
- }
- (void)chkdq(ip, -change, 1);
- (void)chkiq(ip->i_dev, ip, ip->i_uid, 1);
+ else
+ change = ip->i_blocks;
+ (void) chkdq(ip, -change, 1);
+ (void) chkiq(ip->i_dev, ip, ip->i_uid, 1);
dqrele(ip->i_dquot);
#endif
- /*
- * keep uid/gid's in sane range -- no err,
- * so chown(file, uid, -1) will do something useful
- */
- if (uid >= 0 && uid <= 32767) /* should have a constant */
- ip->i_uid = uid;
- if (gid >= 0 && gid <= 32767) /* same here */
- ip->i_gid = gid;
+ ip->i_uid = uid;
+ ip->i_gid = gid;
ip->i_flag |= ICHG;
if (u.u_ruid != 0)
ip->i_mode &= ~(ISUID|ISGID);
#ifdef QUOTA
ip->i_dquot = inoquota(ip);
- (void)chkdq(ip, change, 1);
- (void)chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
+ (void) chkdq(ip, change, 1);
+ (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
+ return (u.u_error); /* should == 0 ALWAYS !! */
+#else
+ return (0);
#endif
}
+#ifndef NOCOMPAT
/*
* Set IUPD and IACC times on file.
* Can't set ICHG.
register struct a {
char *fname;
time_t *tptr;
- } *uap;
+ } *uap = (struct a *)u.u_ap;
register struct inode *ip;
time_t tv[2];
struct timeval tv0, tv1;
- uap = (struct a *)u.u_ap;
if ((ip = owner(1)) == NULL)
return;
- u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv));
+ u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
if (u.u_error == 0) {
ip->i_flag |= IACC|IUPD|ICHG;
tv0.tv_sec = tv[0]; tv0.tv_usec = 0;
}
iput(ip);
}
+#endif
+
+utimes()
+{
+ register struct a {
+ char *fname;
+ struct timeval *tptr;
+ } *uap = (struct a *)u.u_ap;
+ register struct inode *ip;
+ struct timeval tv[2];
+
+ if ((ip = owner(1)) == NULL)
+ return;
+ u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
+ if (u.u_error == 0) {
+ ip->i_flag |= IACC|IUPD|ICHG;
+ iupdat(ip, &tv[0], &tv[1], 0);
+ }
+ iput(ip);
+}
/*
* Flush any pending I/O.
int error = 0;
uap = (struct a *)u.u_ap;
- ip = namei(uchar, LOOKUP | LOCKPARENT, 0);
+ ip = namei(uchar, DELETE | LOCKPARENT, 0);
if (ip == NULL)
return;
dp = u.u_pdir;
d = &u.u_dent;
/*
- * Avoid "." and ".." for obvious reasons.
+ * Avoid ".", "..", and aliases of "." for obvious reasons.
*/
- if (d->d_name[0] == '.') {
- if (d->d_namlen == 1 ||
- (d->d_namlen == 2 && d->d_name[1] == '.')) {
+ if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
+ (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
+ (dp == ip)) {
+ iput(dp);
+ if (dp == ip)
+ irele(ip);
+ else
iput(ip);
- u.u_error = EINVAL;
- return;
- }
+ u.u_error = EINVAL;
+ return;
}
oldparent = dp->i_number;
doingdirectory++;
}
- irele(dp);
+ iput(dp);
/*
* 1) Bump link count while we're moving stuff
goto out;
}
dp = u.u_pdir;
+ /*
+ * If ".." must be changed (ie the directory gets a new
+ * parent) then the user must have write permission.
+ */
+ parentdifferent = oldparent != dp->i_number;
+ if (doingdirectory && parentdifferent && access(ip, IWRITE))
+ goto bad;
/*
* 2) If target doesn't exist, link the target
* to the source and unlink the source.
* entry to reference the source inode and
* expunge the original entry's existence.
*/
- parentdifferent = oldparent != dp->i_number;
if (xp == NULL) {
if (dp->i_dev != ip->i_dev) {
error = EXDEV;
goto bad;
}
+ /*
+ * Disallow rename(foo, foo/bar).
+ */
+ if (dp->i_number == ip->i_number) {
+ error = EEXIST;
+ goto bad;
+ }
/*
* Account for ".." in directory.
* When source and destination have the
dp->i_flag |= ICHG;
iupdat(dp, &time, &time, 1);
}
- direnter(ip);
- if (u.u_error) {
- error = u.u_error;
+ error = direnter(ip);
+ if (error)
goto out;
- }
} else {
if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
error = EXDEV;
goto bad;
}
+ /*
+ * Short circuit rename(foo, foo).
+ */
+ if (xp->i_number == ip->i_number)
+ 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 = u.u_pdir->i_gid;
+ if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
+ ip->i_mode &= ~ISGID;
#ifdef QUOTA
ip->i_dquot = inoquota(ip);
#endif
* Make sure inode goes to disk before directory entry.
*/
iupdat(ip, &time, &time, 1);
- direnter(ip);
+ u.u_error = direnter(ip);
if (u.u_error) {
/*
- * write error occurred trying to update directory
- * so must deallocate the inode
+ * Write error occurred trying to update directory
+ * so must deallocate the inode.
*/
ip->i_nlink = 0;
ip->i_flag |= ICHG;