-/* ufs_vnops.c 4.44 82/12/19 */
+/* ufs_vnops.c 4.50 83/02/10 */
#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_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;
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;
} *uap;
register struct inode *ip, *xp, *dp;
int oldparent, parentdifferent, doingdirectory;
+ int error = 0;
uap = (struct a *)u.u_ap;
ip = namei(uchar, LOOKUP | LOCKPARENT, 0);
if (d->d_name[0] == '.') {
if (d->d_namlen == 1 ||
(d->d_namlen == 2 && d->d_name[1] == '.')) {
- u.u_error = EINVAL;
iput(ip);
+ u.u_error = EINVAL;
return;
}
}
*/
u.u_dirp = (caddr_t)uap->to;
xp = namei(uchar, CREATE | LOCKPARENT, 0);
- if (u.u_error)
+ if (u.u_error) {
+ error = u.u_error;
goto out;
+ }
dp = u.u_pdir;
/*
* 2) If target doesn't exist, link the target
parentdifferent = oldparent != dp->i_number;
if (xp == NULL) {
if (dp->i_dev != ip->i_dev) {
- u.u_error = EXDEV;
+ error = EXDEV;
+ goto bad;
+ }
+ /*
+ * Disallow rename(foo, foo/bar).
+ */
+ if (dp->i_number == ip->i_number) {
+ error = EEXIST;
goto bad;
}
/*
dp->i_flag |= ICHG;
iupdat(dp, &time, &time, 1);
}
- direnter(ip);
- if (u.u_error)
+ error = direnter(ip);
+ if (error)
goto out;
} else {
if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
- u.u_error = EXDEV;
+ error = EXDEV;
goto bad;
}
/*
- * Target must be empty if a directory.
+ * 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)) {
- u.u_error = ENOTEMPTY;
+ if (!dirempty(xp) || xp->i_nlink > 2) {
+ error = ENOTEMPTY;
goto bad;
}
if (!doingdirectory) {
- u.u_error = ENOTDIR;
+ error = ENOTDIR;
goto bad;
}
} else if (doingdirectory) {
- u.u_error = EISDIR;
+ error = EISDIR;
goto bad;
}
dirrewrite(dp, ip);
- if (u.u_error)
+ if (u.u_error) {
+ error = u.u_error;
goto bad1;
+ }
/*
- * If this is a directory we know it is
- * empty and we can squash the inode and
- * any space associated with it. Otherwise,
- * we've got a plain file and the link count
- * simply needs to be adjusted.
+ * 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) {
- xp->i_nlink = 0;
+ if (--xp->i_nlink != 0)
+ panic("rename: linked directory");
itrunc(xp, (u_long)0);
- } else
- xp->i_nlink--;
+ }
xp->i_flag |= ICHG;
iput(xp);
+ xp = NULL;
}
/*
ip->i_nlink--;
ip->i_flag |= ICHG;
}
+ if (error == 0) /* conservative */
+ error = u.u_error;
}
irele(ip);
if (dp)
* and a lot shorter than when it was done
* in a user process.
*/
- if (doingdirectory && parentdifferent && u.u_error == 0) {
+ if (doingdirectory && parentdifferent && error == 0) {
struct dirtemplate dirbuf;
u.u_dirp = uap->to;
printf("rename: .. not a directory\n");
goto stuck;
}
- u.u_error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
+ error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
- if (u.u_error == 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);
irele(dp);
iput(ip);
}
- return;
+ goto done;
+
bad:
- iput(u.u_pdir);
+ iput(dp);
bad1:
if (xp)
- irele(xp);
+ iput(xp);
out:
ip->i_nlink--;
ip->i_flag |= ICHG;
irele(ip);
+done:
+ if (error)
+ u.u_error = error;
}
/*
* 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;