aboutsummaryrefslogtreecommitdiff
path: root/libdiskfs/dir-renamed.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdiskfs/dir-renamed.c')
-rw-r--r--libdiskfs/dir-renamed.c62
1 files changed, 35 insertions, 27 deletions
diff --git a/libdiskfs/dir-renamed.c b/libdiskfs/dir-renamed.c
index 6ef96ee3..79381b2c 100644
--- a/libdiskfs/dir-renamed.c
+++ b/libdiskfs/dir-renamed.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,95,96,97,98,99,2001,2003 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -31,8 +31,7 @@ checkpath(struct node *source,
{
error_t err;
struct node *np;
-
- np = target;
+
for (np = target, err = 0;
/* nothing */;
/* This special lookup does a diskfs_nput on its first argument
@@ -44,20 +43,20 @@ checkpath(struct node *source,
diskfs_nput (np);
return err;
}
-
+
if (np == source)
{
diskfs_nput (np);
return EINVAL;
}
-
+
if (np == diskfs_root_node)
{
diskfs_nput (np);
return 0;
}
}
-}
+}
/* Rename directory node FNP (whose parent is FDP, and which has name
FROMNAME in that directory) to have name TONAME inside directory
@@ -67,9 +66,9 @@ checkpath(struct node *source,
routine. FROMCRED and TOCRED are the users responsible for
FDP/FNP and TDP respectively. */
error_t
-diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
- struct node *tdp, char *toname, struct protid *fromcred,
- struct protid *tocred)
+diskfs_rename_dir (struct node *fdp, struct node *fnp, const char *fromname,
+ struct node *tdp, const char *toname,
+ struct protid *fromcred, struct protid *tocred)
{
error_t err;
struct node *tnp, *tmpnp;
@@ -81,32 +80,40 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
diskfs_nref (tdp); /* reference and lock will get consumed by
checkpath */
err = checkpath (fnp, tdp, tocred);
-
+
if (err)
return err;
-
+
/* Now, lock the parent directories. This is legal because tdp is not
a child of fnp (guaranteed by checkpath above). */
mutex_lock (&fdp->lock);
if (fdp != tdp)
mutex_lock (&tdp->lock);
-
+
/* 1: Lookup target; if it exists, make sure it's an empty directory. */
ds = buf;
err = diskfs_lookup (tdp, toname, RENAME, &tnp, ds, tocred);
-
+ assert (err != EAGAIN); /* <-> assert (TONAME != "..") */
+
if (tnp == fnp)
{
diskfs_drop_dirstat (tdp, ds);
- diskfs_nrele (tnp);
+ diskfs_nput (tnp);
mutex_unlock (&tdp->lock);
if (fdp != tdp)
mutex_unlock (&fdp->lock);
return 0;
}
-
- /* Now we can safely lock fnp */
- mutex_lock (&fnp->lock);
+
+ /* Check permissions to remove FROMNAME and lock FNP. */
+ tmpds = alloca (diskfs_dirstat_size);
+ err = diskfs_lookup (fdp, fromname, REMOVE, &tmpnp, tmpds, fromcred);
+ assert (!tmpnp || tmpnp == fnp);
+ if (tmpnp)
+ diskfs_nrele (tmpnp);
+ diskfs_drop_dirstat (fdp, tmpds);
+ if (err)
+ goto out;
if (tnp)
{
@@ -114,7 +121,7 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
err = ENOTDIR;
else if (!diskfs_dirempty (tnp, tocred))
err = ENOTEMPTY;
- }
+ }
if (err && err != ENOENT)
goto out;
@@ -131,24 +138,24 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
tdp->dn_set_ctime = 1;
if (diskfs_synchronous)
diskfs_node_update (tdp, 1);
-
+
tmpds = alloca (diskfs_dirstat_size);
- err = diskfs_lookup (fnp, "..", RENAME | SPEC_DOTDOT,
+ err = diskfs_lookup (fnp, "..", RENAME | SPEC_DOTDOT,
&tmpnp, tmpds, fromcred);
assert (err != ENOENT);
- assert (tmpnp == fdp);
if (err)
{
diskfs_drop_dirstat (fnp, tmpds);
goto out;
}
+ assert (tmpnp == fdp);
err = diskfs_dirrewrite (fnp, fdp, tdp, "..", tmpds);
if (diskfs_synchronous)
diskfs_file_update (fnp, 1);
if (err)
goto out;
-
+
fdp->dn_stat.st_nlink--;
fdp->dn_set_ctime = 1;
if (diskfs_synchronous)
@@ -170,7 +177,7 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
fnp->dn_stat.st_nlink++;
fnp->dn_set_ctime = 1;
diskfs_node_update (fnp, 1);
-
+
if (tnp)
{
err = diskfs_dirrewrite (tdp, tnp, fnp, toname, ds);
@@ -198,11 +205,12 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
ds = buf;
mutex_unlock (&fnp->lock);
err = diskfs_lookup (fdp, fromname, REMOVE, &tmpnp, ds, fromcred);
- assert (tmpnp == fnp);
- diskfs_nrele (tmpnp);
+ assert (!tmpnp || tmpnp == fnp);
+ if (tmpnp)
+ diskfs_nrele (tmpnp);
if (err)
goto out;
-
+
diskfs_dirremove (fdp, fnp, fromname, ds);
ds = 0;
fnp->dn_stat.st_nlink--;