diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2007-03-25 09:52:57 +0200 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2007-03-25 09:52:57 +0200 |
commit | 1efda4faf3878d180a13a94cadc690f2a95090b1 (patch) | |
tree | eccdf744921edfb7b4eea958a2fd2c76e26af4be /src/copy.c | |
parent | de730249777c65b2c75502b00159400eda8dacf9 (diff) | |
download | coreutils-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.c | 20 |
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 ())); } |