summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2006-06-26 13:02:01 +0000
committerJim Meyering <jim@meyering.net>2006-06-26 13:02:01 +0000
commit78b166d1b163df894d567b79d3bb5744156fb0fe (patch)
tree7f91488762f0ce8af7959d3c89a09ba9904d1cbf
parent9cabe37ac9a127f76e1f414ed8c297e3bf32feaa (diff)
downloadcoreutils-78b166d1b163df894d567b79d3bb5744156fb0fe.tar.xz
* NEWS: rm no longer fails to remove an empty, unreadable directory
* src/remove.c (remove_cwd_entries): If we can't open a directory, and the failure is not being ignored, try to remove the directory with rmdir (aka unlinkat-with-AT_REMOVEDIR), in case it's empty. Problem report and test case from Paul Eggert in <http://article.gmane.org/gmane.comp.gnu.core-utils.bugs/7425>. * tests/rm/empty-inacc: New test, for the above.
-rw-r--r--ChangeLog8
-rw-r--r--NEWS2
-rw-r--r--src/remove.c28
-rwxr-xr-xtests/rm/empty-inacc8
4 files changed, 41 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index 2efa74a90..a55c5034d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2006-06-26 Jim Meyering <jim@meyering.net>
+ * NEWS: rm no longer fails to remove an empty, unreadable directory
+ * src/remove.c (remove_cwd_entries): If we can't open a directory,
+ and the failure is not being ignored, try to remove the directory
+ with rmdir (aka unlinkat-with-AT_REMOVEDIR), in case it's empty.
+ Problem report and test case from Paul Eggert in
+ <http://article.gmane.org/gmane.comp.gnu.core-utils.bugs/7425>.
+ * tests/rm/empty-inacc: New test, for the above.
+
Avoid a segfault for wc --files0=- < /dev/null.
* src/wc.c (compute_number_width): Return right away if nfiles == 0.
diff --git a/NEWS b/NEWS
index 3763af531..2a0a9067a 100644
--- a/NEWS
+++ b/NEWS
@@ -72,6 +72,8 @@ GNU coreutils NEWS -*- outline -*-
rm --interactive now takes an optional argument, although the
default of using no argument still acts like -i.
+ rm no longer fails to remove an empty, unreadable directory
+
sort now reports incompatible options (e.g., -i and -n) rather than
silently ignoring one of them.
diff --git a/src/remove.c b/src/remove.c
index bfb0a3264..076ad64c3 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -1125,13 +1125,28 @@ remove_cwd_entries (DIR **dirp,
x, errno, subdir_sb, ds, NULL);
if (subdir_dirp == NULL)
{
+ status = RM_ERROR;
+
/* CAUTION: this test and diagnostic are identical to
those following the other use of fd_to_subdirp. */
- if (errno != ENOENT || !x->ignore_missing_files)
- error (0, errno,
- _("cannot remove %s"), quote (full_filename (f)));
- AD_mark_as_unremovable (ds, f);
- status = RM_ERROR;
+ if (errno == ENOENT && x->ignore_missing_files)
+ {
+ /* With -f, don't report "file not found". */
+ }
+ else
+ {
+ /* Upon fd_to_subdirp failure, try to remove F directly,
+ in case it's just an empty directory. */
+ int saved_errno = errno;
+ if (unlinkat (dirfd (*dirp), f, AT_REMOVEDIR) == 0)
+ status = RM_OK;
+ else
+ error (0, saved_errno,
+ _("cannot remove %s"), quote (full_filename (f)));
+ }
+
+ if (status == RM_ERROR)
+ AD_mark_as_unremovable (ds, f);
break;
}
@@ -1214,6 +1229,9 @@ remove_dir (int fd_cwd, Dirstack_state *ds, char const *dir,
{
/* If fd_to_subdirp fails due to permissions, then try to
remove DIR via rmdir, in case it's just an empty directory. */
+ /* This use of rmdir just works, at least in the sole test I
+ have that exercises this code, but it'll soon go, to be
+ replaced by a use of unlinkat-with-AT_REMOVEDIR. */
if (rmdir (dir) == 0)
return RM_OK;
diff --git a/tests/rm/empty-inacc b/tests/rm/empty-inacc
index 02da7257c..6c009759f 100755
--- a/tests/rm/empty-inacc
+++ b/tests/rm/empty-inacc
@@ -18,6 +18,10 @@ mkdir -p $tmp || framework_failure=1
cd $tmp || framework_failure=1
mkdir -m0 inacc || framework_failure=1
+# Also exercise the different code path that's taken for a directory
+# that is empty (hence removable) and unreadable.
+mkdir -m a-r -p a/unreadable
+
if test $framework_failure = 1; then
echo "$0: failure in testing framework" 1>&2
(exit 1); exit 1
@@ -29,4 +33,8 @@ fail=0
rm -rf inacc || fail=1
test -d inacc && fail=1
+# This would fail for e.g., coreutils-5.97.
+rm -rf a || fail=1
+test -d a && fail=1
+
(exit $fail); exit $fail