]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
Fix bug where "rm" gave up too easily, reported by Dan Jacobsen in
authorJim Meyering <jim@meyering.net>
Sat, 8 May 2004 12:49:22 +0000 (12:49 +0000)
committerJim Meyering <jim@meyering.net>
Sat, 8 May 2004 12:49:22 +0000 (12:49 +0000)
<http://mail.gnu.org/archive/html/bug-coreutils/2004-05/msg00013.html>.

(remove_entry): Check for errno values like ENOENT
that show the file cannot be directory, instead of for errno
values like EPERM that show the file might be a directory.  This
is necessary because, when a single unlink() call has multiple
reasons to fail, it can set errno to any of those reasons; it's
only the rare errno value like ENOENT that excludes all the other
possible reasons to fail even when the file is a directory.
(remove_cwd_entries): Don't attempt chdir if the file is known
to not be a directory.
(remove_dir): Use the same method that remove_cwd_entries uses
(for some reason they differed).  Don't assert that saved_errno
must be EPERM; it might be just about anything.

src/remove.c

index a83fc7979b6fabf5b4980b65386734528680b4c1..ddd634e2a730ed443c50a9f1762c5734ecb817c6 100644 (file)
@@ -762,14 +762,12 @@ remove_entry (Dirstack_state const *ds, char const *filename,
 
   DO_UNLINK (filename, x);
 
-  /* Accept either EISDIR or EPERM as an indication that FILENAME may be
-     a directory.  POSIX says that unlink must set errno to EPERM when it
-     fails to remove a directory, while Linux-2.4.18 sets it to EISDIR.  */
-  if ((errno != EISDIR && errno != EPERM) || ! x->recursive)
+  if (! x->recursive
+      || errno == ENOENT || errno == ENOTDIR
+      || errno == ELOOP || errno == ENAMETOOLONG)
     {
-      /* some other error code.  Report it and fail.
-        Likewise, if we're trying to remove a directory without
-        the --recursive option.  */
+      /* Either --recursive is not in effect, or the file cannot be a
+        directory.  Report the unlink problem and fail.  */
       error (0, errno, _("cannot remove %s"),
             quote (full_filename (filename)));
       return RM_ERROR;
@@ -871,8 +869,7 @@ remove_cwd_entries (Dirstack_state *ds, char **subdir, struct stat *subdir_sb,
        case RM_NONEMPTY_DIR:
          {
            /* Save a copy of errno, in case the preceding unlink (from
-              remove_entry's DO_UNLINK) of a non-directory failed due
-              to EPERM.  */
+              remove_entry's DO_UNLINK) of a non-directory failed.  */
            int saved_errno = errno;
 
            /* Record dev/ino of F so that we can compare
@@ -882,7 +879,8 @@ remove_cwd_entries (Dirstack_state *ds, char **subdir, struct stat *subdir_sb,
              error (EXIT_FAILURE, errno, _("cannot lstat %s"),
                     quote (full_filename (f)));
 
-           if (chdir (f))
+           errno = ENOTDIR;
+           if (! S_ISDIR (subdir_sb->st_mode) || chdir (f) != 0)
              {
                /* It is much more common that we reach this point for an
                   inaccessible directory.  Hence the second diagnostic, below.
@@ -989,14 +987,11 @@ remove_dir (Dirstack_state *ds, char const *dir, struct saved_cwd **cwd_state,
       return RM_ERROR;
     }
 
-  if (chdir (dir))
+  errno = ENOTDIR;
+  if (! S_ISDIR (dir_sb.st_mode) || chdir (dir) != 0)
     {
-      if (! S_ISDIR (dir_sb.st_mode))
+      if (errno == ENOTDIR)
        {
-         /* This happens on Linux-2.4.18 when a non-privileged user tries
-            to delete a file that is owned by another user in a directory
-            like /tmp that has the S_ISVTX flag set.  */
-         assert (saved_errno == EPERM);
          error (0, saved_errno,
                 _("cannot remove %s"), quote (full_filename (dir)));
        }