summaryrefslogtreecommitdiff
path: root/src/remove.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/remove.c')
-rw-r--r--src/remove.c97
1 files changed, 30 insertions, 67 deletions
diff --git a/src/remove.c b/src/remove.c
index f44a9821..cdbbec5b 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -1,5 +1,5 @@
/* remove.c -- core functions for removing files and directories
- Copyright (C) 1988-2012 Free Software Foundation, Inc.
+ Copyright (C) 1988-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -88,20 +88,6 @@ cache_stat_init (struct stat *st)
return st;
}
-/* Return true if *ST has been statted. */
-static inline bool
-cache_statted (struct stat *st)
-{
- return (st->st_size != -1);
-}
-
-/* Return true if *ST has been statted successfully. */
-static inline bool
-cache_stat_ok (struct stat *st)
-{
- return (0 <= st->st_size);
-}
-
/* Return 1 if FILE is an unwritable non-symlink,
0 if it is writable or some other type of file,
-1 and set errno if there is some problem in determining the answer.
@@ -204,6 +190,13 @@ prompt (FTS const *fts, FTSENT const *ent, bool is_dir,
int dirent_type = is_dir ? DT_DIR : DT_UNKNOWN;
int write_protected = 0;
+ bool is_empty = false;
+ if (is_empty_p)
+ {
+ is_empty = is_empty_dir (fd_cwd, filename);
+ *is_empty_p = is_empty ? T_YES : T_NO;
+ }
+
/* When nonzero, this indicates that we failed to remove a child entry,
either because the user declined an interactive prompt, or due to
some other failure, like permissions. */
@@ -252,7 +245,10 @@ prompt (FTS const *fts, FTSENT const *ent, bool is_dir,
break;
case DT_DIR:
- if (!x->recursive)
+ /* Unless we're either deleting directories or deleting
+ recursively, we want to raise an EISDIR error rather than
+ prompting the user */
+ if ( ! (x->recursive || (x->remove_empty_directories && is_empty)))
{
write_protected = -1;
wp_errno = EISDIR;
@@ -268,15 +264,6 @@ prompt (FTS const *fts, FTSENT const *ent, bool is_dir,
return RM_ERROR;
}
- bool is_empty;
- if (is_empty_p)
- {
- is_empty = is_empty_dir (fd_cwd, filename);
- *is_empty_p = is_empty ? T_YES : T_NO;
- }
- else
- is_empty = false;
-
/* Issue the prompt. */
if (dirent_type == DT_DIR
&& mode == PA_DESCEND_INTO_DIR
@@ -311,36 +298,6 @@ prompt (FTS const *fts, FTSENT const *ent, bool is_dir,
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.
- *ST is FILENAME's tstatus.
- Do not modify errno. */
-static inline bool
-is_dir_lstat (int fd_cwd, char const *filename, struct stat *st)
-{
- int saved_errno = errno;
- bool is_dir =
- (cache_fstatat (fd_cwd, filename, st, AT_SYMLINK_NOFOLLOW) == 0
- && S_ISDIR (st->st_mode));
- errno = saved_errno;
- 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;
-}
-
/* When a function like unlink, rmdir, or fstatat fails with an errno
value of ERRNUM, return true if the specified file system object
is guaranteed not to exist; otherwise, return false. */
@@ -435,11 +392,15 @@ excise (FTS *fts, FTSENT *ent, struct rm_options const *x, bool is_dir)
if (ignorable_missing (x, errno))
return RM_OK;
- /* When failing to rmdir an unreadable directory, the typical
- errno value is EISDIR, but that is not as useful to the user
- as the errno value from the failed open (probably EPERM).
- Use the earlier, more descriptive errno value. */
- if (ent->fts_info == FTS_DNR)
+ /* When failing to rmdir an unreadable directory, we see errno values
+ like EISDIR or ENOTDIR (or, on Solaris 10, EEXIST), but they would be
+ meaningless in a diagnostic. When that happens and the errno value
+ from the failed open is EPERM or EACCES, use the earlier, more
+ descriptive errno value. */
+ if (ent->fts_info == FTS_DNR
+ && (errno == ENOTEMPTY || errno == EISDIR || errno == ENOTDIR
+ || errno == EEXIST)
+ && (ent->fts_errno == EPERM || ent->fts_errno == EACCES))
errno = ent->fts_errno;
error (0, errno, _("cannot remove %s"), quote (ent->fts_path));
mark_ancestor_dirs (ent);
@@ -458,11 +419,16 @@ rm_fts (FTS *fts, FTSENT *ent, struct rm_options const *x)
switch (ent->fts_info)
{
case FTS_D: /* preorder directory */
- if (! x->recursive)
+ if (! x->recursive
+ && !(x->remove_empty_directories
+ && is_empty_dir (fts->fts_cwd_fd, ent->fts_accpath)))
{
- /* This is the first (pre-order) encounter with a directory.
- Not recursive, so arrange to skip contents. */
- error (0, EISDIR, _("cannot remove %s"), quote (ent->fts_path));
+ /* This is the first (pre-order) encounter with a directory
+ that we cannot delete.
+ Not recursive, and it's not an empty directory (if we're removing
+ them) so arrange to skip contents. */
+ int err = x->remove_empty_directories ? ENOTEMPTY : EISDIR;
+ error (0, err, _("cannot remove %s"), quote (ent->fts_path));
mark_ancestor_dirs (ent);
fts_skip_tree (fts, ent);
return RM_ERROR;
@@ -471,9 +437,6 @@ rm_fts (FTS *fts, FTSENT *ent, struct rm_options const *x)
/* Perform checks that can apply only for command-line arguments. */
if (ent->fts_level == FTS_ROOTLEVEL)
{
- if (strip_trailing_slashes (ent->fts_path))
- ent->fts_pathlen = strlen (ent->fts_path);
-
/* If the basename of a command line argument is "." or "..",
diagnose it and do nothing more with that argument. */
if (dot_or_dotdot (last_component (ent->fts_accpath)))