aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2014-09-13 14:48:37 -0500
committerRob Landley <rob@landley.net>2014-09-13 14:48:37 -0500
commite1366f02fea3cb035cc4ed0b59d12f1962b6ebfd (patch)
treebf70ad84930fdf5d665745569374901ef087a4cf
parent8aa87ab9b4ee68eec75af26d550fbcfb732d660f (diff)
downloadtoybox-e1366f02fea3cb035cc4ed0b59d12f1962b6ebfd.tar.gz
Bug report from luckboy: rm -f on a broken symlink didn't work because our "does it exist" test (to avoid errors on rm -f of nonexistent files) said it didn't.
The fix: replace the access() with unlink(), which produces the same "does not exist" errno and has the added bonus of acting as a fastpath for rm -f on non-directories. (And since it produces a different error on directories, falls through to the old behavior there.) Most of this commit is comment updates explaining being subtle. :)
-rw-r--r--toys/posix/rm.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/toys/posix/rm.c b/toys/posix/rm.c
index 2f40106f..6c984046 100644
--- a/toys/posix/rm.c
+++ b/toys/posix/rm.c
@@ -88,11 +88,15 @@ void rm_main(void)
continue;
}
- // There's a race here where a file removed between this access and
+ // Files that already don't exist aren't errors for -f, so try a quick
+ // unlink now to see if it succeeds or reports that it didn't exist.
+ if ((toys.optflags & FLAG_f) && (!unlink(*s) || errno == ENOENT))
+ continue;
+
+ // There's a race here where a file removed between the above check and
// dirtree's stat would report the nonexistence as an error, but that's
// not a normal "it didn't exist" so I'm ok with it.
- if ((toys.optflags & FLAG_f) && (access(*s, F_OK) && errno == ENOENT))
- continue;
+
dirtree_read(*s, do_rm);
}
}