summaryrefslogtreecommitdiff
path: root/src/remove.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2005-11-02 09:47:39 +0000
committerJim Meyering <jim@meyering.net>2005-11-02 09:47:39 +0000
commit588df316d95e633dde9b878745c451bc7d2ad306 (patch)
treeaf18ed522b0b1fe970f8ed958e8772b8aff0423c /src/remove.c
parent4db5b5cf1191005af254f174baa18a241cad7aab (diff)
downloadcoreutils-588df316d95e633dde9b878745c451bc7d2ad306.tar.xz
(remove_entry): Emit a better diagnostic when rm
(without -r) fails to remove a directory on a non-Linux system. This change affects only newer Solaris systems (with priv_* functions like priv_allocset). Reported by Keith Thompson.
Diffstat (limited to 'src/remove.c')
-rw-r--r--src/remove.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/src/remove.c b/src/remove.c
index 6572245fd..52ef3b625 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -657,6 +657,19 @@ prompt (Dirstack_state const *ds, char const *filename,
return RM_OK;
}
+/* Return true if FILENAME is a directory (and not a symlink to a directory).
+ Otherwise, including the case in which lstat fails, return false.
+ Do not modify errno. */
+static inline bool
+is_dir_lstat (char const *filename)
+{
+ struct stat sbuf;
+ int saved_errno = errno;
+ bool is_dir = lstat (filename, &sbuf) == 0 && S_ISDIR (sbuf.st_mode);
+ errno = saved_errno;
+ return is_dir;
+}
+
#if HAVE_STRUCT_DIRENT_D_TYPE
/* True if the type of the directory entry D is known. */
@@ -760,6 +773,12 @@ remove_entry (Dirstack_state const *ds, char const *filename,
DO_UNLINK (filename, x);
+ /* Upon a failed attempt to unlink a directory, most non-Linux systems
+ set errno to the POSIX-required value EPERM. In that case, change
+ errno to EISDIR so that we emit a better diagnostic. */
+ if (! x->recursive && errno == EPERM && is_dir_lstat (filename))
+ errno = EISDIR;
+
if (! x->recursive
|| errno == ENOENT || errno == ENOTDIR
|| errno == ELOOP || errno == ENAMETOOLONG)