* NEWS: rm no longer fails to remove an empty, unreadable directory
authorJim Meyering <jim@meyering.net>
Mon, 26 Jun 2006 13:02:01 +0000 (13:02 +0000)
committerJim Meyering <jim@meyering.net>
Mon, 26 Jun 2006 13:02:01 +0000 (13:02 +0000)
* 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.

ChangeLog
NEWS
src/remove.c
tests/rm/empty-inacc

index 2efa74a..a55c503 100644 (file)
--- 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 3763af5..2a0a906 100644 (file)
--- 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.
 
index bfb0a32..076ad64 100644 (file)
@@ -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;
 
index 02da725..6c00975 100755 (executable)
@@ -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