summaryrefslogtreecommitdiff
path: root/src/copy.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2007-03-25 09:52:57 +0200
committerJim Meyering <jim@meyering.net>2007-03-25 09:52:57 +0200
commit1efda4faf3878d180a13a94cadc690f2a95090b1 (patch)
treeeccdf744921edfb7b4eea958a2fd2c76e26af4be /src/copy.c
parentde730249777c65b2c75502b00159400eda8dacf9 (diff)
downloadcoreutils-1efda4faf3878d180a13a94cadc690f2a95090b1.tar.xz
Avoid the need for euidaccess and/or lstat on every directory entry
with 'rm -r dir' (without -f), if we are root, or if we are removing a directory tree that is full of symbolic links. * bootstrap.conf (gnulib_modules): Add write-any-file. * src/copy.c: Include write-any-file.h. (UNWRITABLE): Remove macro, replacing with.... (writable_destination): New function, which uses can_write_any_file to avoid the need for euidaccess when we are privileged. (overwrite_prompt, abandon_move): Use it. * src/remove.c: Include write-any-file.h. (D_TYPE): New macro. (DT_UNKNOWN, DT_DIR, DT_LNK) [!HAVE_STRUCT_DIRENT_D_TYPE]: New macros. (write_protected_non_symlink): Don't bother to stat if we can write any file. (prompt): New arg PDIRENT_TYPE. All callers changed. Use readdir dirent type to avoid the need for 'lstat' on each directory entry in cases like 'rm -r dir', if we are root, or if the tree is full of symbolic links. (DT_IS_KNOWN, DT_MUST_BE): Remove. (remove_entry): New arg DIRENT_TYPE_ARG. All callers changed.
Diffstat (limited to 'src/copy.c')
-rw-r--r--src/copy.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/src/copy.c b/src/copy.c
index 4bdb75cbb..786de2f9e 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -51,6 +51,7 @@
#include "stat-time.h"
#include "utimecmp.h"
#include "utimens.h"
+#include "write-any-file.h"
#include "xreadlink.h"
#include "yesno.h"
@@ -63,11 +64,6 @@
#define SAME_GROUP(A, B) ((A).st_gid == (B).st_gid)
#define SAME_OWNER_AND_GROUP(A, B) (SAME_OWNER (A, B) && SAME_GROUP (A, B))
-#define UNWRITABLE(File_name, File_mode) \
- ( /* euidaccess is not meaningful for symlinks */ \
- ! S_ISLNK (File_mode) \
- && euidaccess (File_name, W_OK) != 0)
-
struct dir_list
{
struct dir_list *parent;
@@ -793,10 +789,20 @@ same_file_ok (char const *src_name, struct stat const *src_sb,
return false;
}
+/* Return true if FILE, with mode MODE, is writable in the sense of 'mv'.
+ Always consider a symbolic link to be writable. */
+static bool
+writable_destination (char const *file, mode_t mode)
+{
+ return (S_ISLNK (mode)
+ || can_write_any_file ()
+ || euidaccess (file, W_OK) == 0);
+}
+
static void
overwrite_prompt (char const *dst_name, struct stat const *dst_sb)
{
- if (euidaccess (dst_name, W_OK) != 0)
+ if (! writable_destination (dst_name, dst_sb->st_mode))
{
char perms[12]; /* "-rwxrwxrwx " ls-style modes. */
strmode (dst_sb->st_mode, perms);
@@ -978,7 +984,7 @@ abandon_move (const struct cp_options *x,
|| ((x->interactive == I_ASK_USER
|| (x->interactive == I_UNSPECIFIED
&& x->stdin_tty
- && UNWRITABLE (dst_name, dst_sb->st_mode)))
+ && ! writable_destination (dst_name, dst_sb->st_mode)))
&& (overwrite_prompt (dst_name, dst_sb), 1)
&& ! yesno ()));
}