diff options
Diffstat (limited to 'src/remove.c')
-rw-r--r-- | src/remove.c | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/src/remove.c b/src/remove.c index aae7a8888..ac1010953 100644 --- a/src/remove.c +++ b/src/remove.c @@ -937,6 +937,21 @@ is_dir_lstat (int fd_cwd, char const *filename, struct stat *st) return is_dir; } +/* Return true if FILENAME is a non-directory. + Otherwise, including the case in which lstat fails, return false. + *ST is FILENAME's tstatus. + Do not modify errno. */ +static inline bool +is_nondir_lstat (int fd_cwd, char const *filename, struct stat *st) +{ + int saved_errno = errno; + bool is_non_dir = + (cache_fstatat (fd_cwd, filename, st, AT_SYMLINK_NOFOLLOW) == 0 + && !S_ISDIR (st->st_mode)); + errno = saved_errno; + return is_non_dir; +} + #define DO_UNLINK(Fd_cwd, Filename, X) \ do \ { \ @@ -1066,7 +1081,9 @@ remove_entry (int fd_cwd, Dirstack_state const *ds, char const *filename, errno = EISDIR; if (! x->recursive - || (cache_stat_ok (st) && !S_ISDIR (st->st_mode))) + || (cache_stat_ok (st) && !S_ISDIR (st->st_mode)) + || (errno == EACCES && is_nondir_lstat (fd_cwd, filename, st)) + ) { if (ignorable_missing (x, errno)) return RM_OK; |