-/* lfs_vnops.c 4.38 82/10/10 */
+/* lfs_vnops.c 4.54 83/03/31 */
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/descrip.h"
#include "../h/uio.h"
#include "../h/socket.h"
+#include "../h/socketvar.h"
+#include "../h/nami.h"
+/*
+ * Change current working directory (``.'').
+ */
chdir()
{
chdirec(&u.u_cdir);
}
+/*
+ * Change notion of root (``/'') directory.
+ */
chroot()
{
chdirec(&u.u_rdir);
}
+/*
+ * Common routine for chroot and chdir.
+ */
chdirec(ipp)
register struct inode **ipp;
{
char *fname;
};
- ip = namei(uchar, 0, 1);
- if(ip == NULL)
+ ip = namei(uchar, LOOKUP, 1);
+ if (ip == NULL)
return;
- if((ip->i_mode&IFMT) != IFDIR) {
+ if ((ip->i_mode&IFMT) != IFDIR) {
u.u_error = ENOTDIR;
goto bad;
}
- if(access(ip, IEXEC))
+ if (access(ip, IEXEC))
goto bad;
iunlock(ip);
if (*ipp)
int flags;
int mode;
} *uap;
- int checkpermissions = 1;
+ int checkpermissions = 1, flags;
uap = (struct a *)u.u_ap;
- if (uap->flags&FCREATE) {
- ip = namei(uchar, 1, 1);
+ flags = uap->flags + 1;
+ if ((flags&FTRUNCATE) && (flags&FWRITE) == 0) {
+ u.u_error = EINVAL;
+ return;
+ }
+ if (flags&FCREATE) {
+ ip = namei(uchar, CREATE, 1);
if (ip == NULL) {
if (u.u_error)
return;
ip = maknode(uap->mode&07777&(~ISVTX));
checkpermissions = 0;
- uap->flags &= ~FTRUNCATE;
+ flags &= ~FTRUNCATE;
}
} else
- ip = namei(uchar, 0, 1);
+ ip = namei(uchar, LOOKUP, 1);
if (ip == NULL)
return;
- open1(ip, ++uap->flags, checkpermissions);
+ open1(ip, flags, checkpermissions);
}
#ifndef NOCOMPAT
} *uap;
uap = (struct a *)u.u_ap;
- ip = namei(uchar, 1, 1);
+ ip = namei(uchar, CREATE, 1);
if (ip == NULL) {
if (u.u_error)
return;
return;
open1(ip, FWRITE, 0);
} else
- open1(ip, FWRITE|FTRUNCATE, 0);
+ open1(ip, FWRITE|FTRUNCATE, 1);
}
#endif
* while doing so in case we block inside flocki.
*/
flags = 0;
- if (mode&(FRDLOCK|FWRLOCK)) {
+ if (mode&(FSHLOCK|FEXLOCK)) {
iunlock(ip);
flags = flocki(ip, 0, mode);
ilock(ip);
goto bad;
}
if (mode&FTRUNCATE)
- itrunc(ip, 0);
+ itrunc(ip, (u_long)0);
iunlock(ip);
if ((fp = falloc()) == NULL)
goto out;
fp->f_type = DTYPE_FILE;
i = u.u_r.r_val1;
fp->f_inode = ip;
- openi(ip, mode);
+ u.u_error = openi(ip, mode);
if (u.u_error == 0) {
u.u_pofile[i] = flags;
return;
uap = (struct a *)u.u_ap;
if (suser()) {
- ip = namei(uchar, 1, 0);
+ ip = namei(uchar, CREATE, 0);
if (ip != NULL) {
u.u_error = EEXIST;
goto out;
} *uap;
uap = (struct a *)u.u_ap;
- ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */
+ ip = namei(uchar, LOOKUP, 1); /* well, this routine is doomed anyhow */
if (ip == NULL)
return;
- if ((ip->i_mode&IFMT)==IFDIR && !suser()) {
+ if ((ip->i_mode&IFMT) == IFDIR && !suser()) {
iput(ip);
return;
}
ip->i_nlink++;
ip->i_flag |= ICHG;
- iupdat(ip, &time.tv_sec, &time.tv_sec, 1);
+ iupdat(ip, &time, &time, 1);
iunlock(ip);
u.u_dirp = (caddr_t)uap->linkname;
- xp = namei(uchar, 1, 0);
+ xp = namei(uchar, CREATE, 0);
if (xp != NULL) {
u.u_error = EEXIST;
iput(xp);
u.u_error = EXDEV;
goto out;
}
- direnter(ip);
+ u.u_error = direnter(ip);
out:
if (u.u_error) {
ip->i_nlink--;
nc++;
}
u.u_dirp = uap->linkname;
- ip = namei(uchar, 1, 0);
+ ip = namei(uchar, CREATE, 0);
if (ip) {
iput(ip);
u.u_error = EEXIST;
if (ip == NULL)
return;
u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0);
+ /* handle u.u_error != 0 */
iput(ip);
}
*/
unlink()
{
- register struct inode *ip, *pp;
struct a {
char *fname;
};
- int unlinkingdot = 0;
+ register struct inode *ip, *dp;
- pp = namei(uchar, 2, 0);
- if (pp == NULL)
+ ip = namei(uchar, DELETE | LOCKPARENT, 0);
+ if (ip == 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())
+ dp = u.u_pdir;
+ if ((ip->i_mode&IFMT) == IFDIR && !suser())
goto out;
/*
* Don't unlink a mounted file.
*/
- if (ip->i_dev != pp->i_dev) {
+ if (ip->i_dev != dp->i_dev) {
u.u_error = EBUSY;
goto out;
}
ip->i_flag |= ICHG;
}
out:
- if (unlinkingdot)
+ if (dp == ip)
irele(ip);
else
iput(ip);
-out1:
- iput(pp);
+ iput(dp);
}
/*
svgid = u.u_gid;
u.u_uid = u.u_ruid;
u.u_gid = u.u_rgid;
- ip = namei(uchar, 0, 1);
+ ip = namei(uchar, LOOKUP, 1);
if (ip != NULL) {
- if (uap->fmode&FACCESS_READ && access(ip, IREAD))
+ if ((uap->fmode&FACCESS_READ) && access(ip, IREAD))
goto done;
- if (uap->fmode&FACCESS_WRITE && access(ip, IWRITE))
+ if ((uap->fmode&FACCESS_WRITE) && access(ip, IWRITE))
goto done;
- if (uap->fmode&FACCESS_EXECUTE && access(ip, IEXEC))
+ if ((uap->fmode&FACCESS_EXECUTE) && access(ip, IEXEC))
goto done;
done:
iput(ip);
} *uap;
uap = (struct a *)u.u_ap;
- ip = namei(uchar, 0, 1);
+ ip = namei(uchar, LOOKUP, 1);
if (ip == NULL)
return;
stat1(ip, uap->sb);
} *uap;
uap = (struct a *)u.u_ap;
- ip = namei(uchar, 0, 0);
+ ip = namei(uchar, LOOKUP, 0);
if (ip == NULL)
return;
stat1(ip, uap->sb);
{
struct stat ds;
- IUPDAT(ip, &time.tv_sec, &time.tv_sec, 0);
+ IUPDAT(ip, &time, &time, 0);
/*
* Copy from inode table
*/
ds.st_rdev = (dev_t)ip->i_rdev;
ds.st_size = ip->i_size;
ds.st_atime = ip->i_atime;
+ ds.st_spare1 = 0;
ds.st_mtime = ip->i_mtime;
+ ds.st_spare2 = 0;
ds.st_ctime = ip->i_ctime;
+ ds.st_spare3 = 0;
/* this doesn't belong here */
if ((ip->i_mode&IFMT) == IFBLK)
ds.st_blksize = BLKDEV_IOSIZE;
ds.st_blksize = MAXBSIZE;
else
ds.st_blksize = ip->i_fs->fs_bsize;
- if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
- u.u_error = EFAULT;
+ ds.st_spare4[0] = ds.st_spare4[1] = ds.st_spare4[2] = 0;
+ u.u_error = copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds));
}
/*
} *uap = (struct a *)u.u_ap;
int resid;
- ip = namei(uchar, 0, 0);
+ ip = namei(uchar, LOOKUP, 0);
if (ip == NULL)
return;
if ((ip->i_mode&IFMT) != IFLNK) {
u.u_r.r_val1 = uap->count - resid;
}
+/*
+ * Change mode of a file given path name.
+ */
chmod()
{
struct inode *ip;
if ((ip = owner(1)) == NULL)
return;
chmod1(ip, uap->fmode);
+ iput(ip);
}
+/*
+ * Change mode of a file given a file descriptor.
+ */
fchmod()
{
struct a {
return;
}
ip = fp->f_inode;
- ilock(ip);
- if (u.u_uid != ip->i_uid && !suser()) {
- iunlock(ip);
+ if (u.u_uid != ip->i_uid && !suser())
return;
- }
+ ilock(ip);
chmod1(ip, uap->fmode);
+ iunlock(ip);
}
+/*
+ * Change the mode on a file.
+ * Inode must be locked before calling.
+ */
chmod1(ip, mode)
register struct inode *ip;
register int mode;
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:
- ;
+ if (!groupmember(ip->i_gid))
+ mode &= ~ISGID;
#ifdef MUSH
- if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 &&
+ if (u.u_quota->q_syflags & QF_UMASK &&
(ip->i_mode & IFMT) != IFCHR)
mode &= ~u.u_cmask;
#endif
ip->i_flag |= ICHG;
if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
xrele(ip);
- iput(ip);
}
+/*
+ * Set ownership given a path name.
+ */
chown()
{
struct inode *ip;
} *uap;
uap = (struct a *)u.u_ap;
- if (!suser() || (ip = owner(0)) == NULL)
+ if ((ip = owner(0)) == NULL)
return;
- chown1(ip, uap->uid, uap->gid);
+ u.u_error = chown1(ip, uap->uid, uap->gid);
+ iput(ip);
}
+/*
+ * Set ownership given a file descriptor.
+ */
fchown()
{
struct a {
return;
}
ip = fp->f_inode;
- ilock(ip);
- if (!suser()) {
- iunlock(ip);
+ if (ip->i_uid != u.u_uid && !suser())
return;
- }
- chown1(ip, uap->uid, uap->gid);
+ ilock(ip);
+ u.u_error = chown1(ip, uap->uid, uap->gid);
+ iunlock(ip);
}
/*
{
#ifdef QUOTA
register long change;
+#endif
+ if (uid == -1)
+ uid = ip->i_uid;
+ if (gid == -1)
+ gid = ip->i_gid;
+ if (u.u_uid && ip->i_gid != gid && !groupmember(gid))
+ return (EPERM);
+#ifdef QUOTA
/*
* This doesn't allow for holes in files (which hopefully don't
* happen often in files that we chown), and is not accurate anyway
change = fragroundup(fs, ip->i_size);
change /= DEV_BSIZE;
}
- chkdq(ip, -change, 1);
- chkiq(ip->i_dev, ip, ip->i_uid, 1);
+ (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);
- chkdq(ip, change, 1);
- chkiq(ip->i_dev, NULL, uid, 1);
+ (void)chkdq(ip, change, 1);
+ (void)chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
+ return (u.u_error);
#endif
- iput(ip);
+ return (0);
}
+#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;
- if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
- u.u_error = EFAULT;
- } else {
+ 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;
+ tv1.tv_sec = tv[1]; tv1.tv_usec = 0;
+ iupdat(ip, &tv0, &tv1, 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.
+ */
sync()
{
- update(0);
+ update();
}
+/*
+ * Apply an advisory lock on a file descriptor.
+ */
flock()
{
struct a {
return;
}
cmd = uap->how;
- flags = u.u_pofile[uap->fd] & (RDLOCK|WRLOCK);
+ flags = u.u_pofile[uap->fd] & (UF_SHLOCK|UF_EXLOCK);
if (cmd&FUNLOCK) {
if (flags == 0) {
u.u_error = EINVAL;
return;
}
funlocki(fp->f_inode, flags);
- u.u_pofile[uap->fd] &= ~(RDLOCK|WRLOCK);
+ u.u_pofile[uap->fd] &= ~(UF_SHLOCK|UF_EXLOCK);
return;
}
/*
* No reason to write lock a file we've already
* write locked, similarly with a read lock.
*/
- if ((flags&WRLOCK) && (cmd&FWRLOCK) ||
- (flags&RDLOCK) && (cmd&FRDLOCK))
+ if ((flags&UF_EXLOCK) && (cmd&FEXLOCK) ||
+ (flags&UF_SHLOCK) && (cmd&FSHLOCK))
return;
u.u_pofile[uap->fd] = flocki(fp->f_inode, u.u_pofile[uap->fd], cmd);
}
+/*
+ * Truncate a file given its path name.
+ */
truncate()
{
struct a {
char *fname;
- int length;
+ u_long length;
} *uap = (struct a *)u.u_ap;
struct inode *ip;
- ip = namei(uchar, 0, 1);
+ ip = namei(uchar, LOOKUP, 1);
if (ip == NULL)
return;
if (access(ip, IWRITE))
goto bad;
}
itrunc(ip, uap->length);
- return;
bad:
iput(ip);
}
+/*
+ * Truncate a file given a file descriptor.
+ */
ftruncate()
{
struct a {
int fd;
- int length;
+ u_long length;
} *uap = (struct a *)u.u_ap;
struct inode *ip;
struct file *fp;
ip = fp->f_inode;
ilock(ip);
itrunc(ip, uap->length);
+ iunlock(ip);
+}
+
+/*
+ * Synch an open file.
+ */
+fsync()
+{
+ struct a {
+ int fd;
+ } *uap = (struct a *)u.u_ap;
+ struct inode *ip;
+ struct file *fp;
+
+ fp = getf(uap->fd);
+ if (fp == NULL)
+ return;
+ if (fp->f_type == DTYPE_SOCKET) {
+ u.u_error = EINVAL;
+ return;
+ }
+ ip = fp->f_inode;
+ ilock(ip);
+ syncip(ip);
+ iunlock(ip);
}
+/*
+ * Rename system call.
+ * rename("foo", "bar");
+ * is essentially
+ * unlink("bar");
+ * link("foo", "bar");
+ * unlink("foo");
+ * but ``atomically''. Can't do full commit without saving state in the
+ * inode on disk which isn't feasible at this time. Best we can do is
+ * always guarantee the target exists.
+ *
+ * Basic algorithm is:
+ *
+ * 1) Bump link count on source while we're linking it to the
+ * target. This also insure the inode won't be deleted out
+ * from underneath us while we work.
+ * 2) Link source to destination. If destination already exists,
+ * delete it first.
+ * 3) Unlink source reference to inode if still around.
+ * 4) If a directory was moved and the parent of the destination
+ * is different from the source, patch the ".." entry in the
+ * directory.
+ *
+ * Source and destination must either both be directories, or both
+ * not be directories. If target is a directory, it must be empty.
+ */
rename()
{
-#ifdef notdef
struct a {
char *from;
char *to;
} *uap;
-#endif
+ register struct inode *ip, *xp, *dp;
+ int oldparent, parentdifferent, doingdirectory;
+ int error = 0;
+
+ uap = (struct a *)u.u_ap;
+ ip = namei(uchar, DELETE | LOCKPARENT, 0);
+ if (ip == NULL)
+ return;
+ dp = u.u_pdir;
+ oldparent = 0, doingdirectory = 0;
+ if ((ip->i_mode&IFMT) == IFDIR) {
+ register struct direct *d;
+
+ d = &u.u_dent;
+ /*
+ * Avoid ".", "..", and aliases of "." for obvious reasons.
+ */
+ 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;
+ }
+ oldparent = dp->i_number;
+ doingdirectory++;
+ }
+ iput(dp);
+
+ /*
+ * 1) Bump link count while we're moving stuff
+ * around. If we crash somewhere before
+ * completing our work, the link count
+ * may be wrong, but correctable.
+ */
+ ip->i_nlink++;
+ ip->i_flag |= ICHG;
+ iupdat(ip, &time, &time, 1);
+ iunlock(ip);
+
+ /*
+ * When the target exists, both the directory
+ * and target inodes are returned locked.
+ */
+ u.u_dirp = (caddr_t)uap->to;
+ xp = namei(uchar, CREATE | LOCKPARENT, 0);
+ if (u.u_error) {
+ error = u.u_error;
+ 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.
+ * Otherwise, rewrite the target directory
+ * entry to reference the source inode and
+ * expunge the original entry's existence.
+ */
+ 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
+ * same parent we don't fool with the
+ * link count -- this isn't required
+ * because we do a similar check below.
+ */
+ if (doingdirectory && parentdifferent) {
+ dp->i_nlink++;
+ dp->i_flag |= ICHG;
+ iupdat(dp, &time, &time, 1);
+ }
+ 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.
+ * Also, insure source and target are
+ * compatible (both directories, or both
+ * not directories).
+ */
+ if ((xp->i_mode&IFMT) == IFDIR) {
+ if (!dirempty(xp) || xp->i_nlink > 2) {
+ error = ENOTEMPTY;
+ goto bad;
+ }
+ if (!doingdirectory) {
+ error = ENOTDIR;
+ goto bad;
+ }
+ } else if (doingdirectory) {
+ error = EISDIR;
+ goto bad;
+ }
+ dirrewrite(dp, ip);
+ if (u.u_error) {
+ error = u.u_error;
+ goto bad1;
+ }
+ /*
+ * Adjust the link count of the target to
+ * reflect the dirrewrite above. If this is
+ * a directory it is empty and there are
+ * no links to it, so we can squash the inode and
+ * any space associated with it. We disallowed
+ * renaming over top of a directory with links to
+ * it above, as we've no way to determine if
+ * we've got a link or the directory itself, and
+ * if we get a link, then ".." will be screwed up.
+ */
+ xp->i_nlink--;
+ if (doingdirectory) {
+ if (--xp->i_nlink != 0)
+ panic("rename: linked directory");
+ itrunc(xp, (u_long)0);
+ }
+ xp->i_flag |= ICHG;
+ iput(xp);
+ xp = NULL;
+ }
+ /*
+ * 3) Unlink the source.
+ */
+ u.u_dirp = uap->from;
+ dp = namei(uchar, DELETE, 0);
+ /*
+ * Insure directory entry still exists and
+ * has not changed since the start of all
+ * this. If either has occured, forget about
+ * about deleting the original entry and just
+ * adjust the link count in the inode.
+ */
+ if (dp == NULL || u.u_dent.d_ino != ip->i_number) {
+ ip->i_nlink--;
+ ip->i_flag |= ICHG;
+ } else {
+ /*
+ * If source is a directory, must adjust
+ * link count of parent directory also.
+ * If target didn't exist and source and
+ * target have the same parent, then we
+ * needn't touch the link count, it all
+ * balances out in the end. Otherwise, we
+ * must do so to reflect deletion of ".."
+ * done above.
+ */
+ if (doingdirectory && (xp != NULL || parentdifferent)) {
+ dp->i_nlink--;
+ dp->i_flag |= ICHG;
+ }
+ if (dirremove()) {
+ ip->i_nlink--;
+ ip->i_flag |= ICHG;
+ }
+ if (error == 0) /* conservative */
+ error = u.u_error;
+ }
+ irele(ip);
+ if (dp)
+ iput(dp);
+
+ /*
+ * 4) Renaming a directory with the parent
+ * different requires ".." to be rewritten.
+ * The window is still there for ".." to
+ * be inconsistent, but this is unavoidable,
+ * and a lot shorter than when it was done
+ * in a user process.
+ */
+ if (doingdirectory && parentdifferent && error == 0) {
+ struct dirtemplate dirbuf;
+
+ u.u_dirp = uap->to;
+ ip = namei(uchar, LOOKUP | LOCKPARENT, 0);
+ if (ip == NULL) {
+ printf("rename: .. went away\n");
+ return;
+ }
+ dp = u.u_pdir;
+ if ((ip->i_mode&IFMT) != IFDIR) {
+ printf("rename: .. not a directory\n");
+ goto stuck;
+ }
+ error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
+ sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
+ if (error == 0) {
+ dirbuf.dotdot_ino = dp->i_number;
+ (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf,
+ sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
+ }
+stuck:
+ irele(dp);
+ iput(ip);
+ }
+ goto done;
+
+bad:
+ iput(dp);
+bad1:
+ if (xp)
+ iput(xp);
+out:
+ ip->i_nlink--;
+ ip->i_flag |= ICHG;
+ irele(ip);
+done:
+ if (error)
+ u.u_error = error;
}
/*
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.tv_sec, &time.tv_sec, 1);
- direnter(ip);
+ iupdat(ip, &time, &time, 1);
+ 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;