summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2006-03-10 21:47:34 +0000
committerJim Meyering <jim@meyering.net>2006-03-10 21:47:34 +0000
commit76d20d82dd1ee35c7d2ad49fb8250ac4eecde43b (patch)
tree0e0b6840f687f41f280769baaba9e643d26510ca
parent6754d7a74f3c04205dc27ee39cc154e429dcfe19 (diff)
downloadcoreutils-76d20d82dd1ee35c7d2ad49fb8250ac4eecde43b.tar.xz
Fix a bug whereby a user with write access to a directory being removed
could cause the removal of that directory to fail with an erroneous diagnostic about a directory cycle. Reported by Vineet Chadha. (AD_pop_and_chdir): If the directory we're about to leave (and try to rmdir) is the one whose dev_ino is being used to detect a cycle, reset cycle_check_state.dev_ino to that of the parent.
-rw-r--r--src/remove.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/src/remove.c b/src/remove.c
index e90db1077..cf46fd2c9 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -391,7 +391,9 @@ ds_free (Dirstack_state *ds)
static void
AD_pop_and_chdir (DIR **dirp, Dirstack_state *ds, char **prev_dir)
{
- enum RM_status old_status = AD_stack_top(ds)->status;
+ struct AD_ent *leaf_dir_ent = AD_stack_top(ds);
+ struct dev_ino leaf_dev_ino = leaf_dir_ent->dev_ino;
+ enum RM_status old_status = leaf_dir_ent->status;
struct AD_ent *top;
/* Get the name of the current (but soon to be `previous') directory
@@ -402,6 +404,16 @@ AD_pop_and_chdir (DIR **dirp, Dirstack_state *ds, char **prev_dir)
pop_dir (ds);
top = AD_stack_top (ds);
+ /* If the directory we're about to leave (and try to rmdir)
+ is the one whose dev_ino is being used to detect a cycle,
+ reset cycle_check_state.dev_ino to that of the parent.
+ Otherwise, once that directory is removed, its dev_ino
+ could be reused in the creation (by some other process)
+ of a directory that this rm process would encounter,
+ which would result in a false-positive cycle indication. */
+ if (SAME_INODE (ds->cycle_check_state.dev_ino, leaf_dev_ino))
+ ds->cycle_check_state.dev_ino = top->dev_ino;
+
/* Propagate any failure to parent. */
UPDATE_STATUS (top->status, old_status);