diff options
author | Jim Meyering <jim@meyering.net> | 2004-05-08 12:49:22 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2004-05-08 12:49:22 +0000 |
commit | 2e83808dd6db78feacef25035fcbadd7f05625c4 (patch) | |
tree | 9802d4fe244c08c74e88672cb4e724c27c318c47 /src/remove.c | |
parent | 198dc407d36fc14325d34d533939653719c64be6 (diff) | |
download | coreutils-2e83808dd6db78feacef25035fcbadd7f05625c4.tar.xz |
Fix bug where "rm" gave up too easily, reported by Dan Jacobsen in
<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.
Diffstat (limited to 'src/remove.c')
-rw-r--r-- | src/remove.c | 27 |
1 files changed, 11 insertions, 16 deletions
diff --git a/src/remove.c b/src/remove.c index a83fc7979..ddd634e2a 100644 --- a/src/remove.c +++ b/src/remove.c @@ -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))); } |