From 811901cb41421e315c4b2e04989fb380ec20cb33 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 Jun 2007 11:58:47 +0200 Subject: A few more symlink-related fixes. Fix a bug triggered by cp --parents and symlinks. Close some race conditions possible when the destination replaces a newly-created file with a symlink. * NEWS: Document that 'cp --parents' no longer mishandles symlinks in file name components of source. * src/copy.c (HAVE_LCHOWN): Default to false. (lchown) [!defined HAVE_LCHOWN]: Define to chown, for convenience. * src/cp.c (lchown) [!HAVE_LCHOWN]: Likewise. * src/install.c (lchown [!HAVE_LCHOWN]: Likewise. * src/copy.c (set_owner): Use lchown instead of chown, for safety in case the file got replaced by a symlink in the meantime. * src/cp.c (re_protect): Likewise. * src/install.c (change_attributes): Likewise. * src/copy.c (copy_internal): Use ordinary C rather than an #if. * src/cp.c (lchown) [!HAVE_LCHOWN]: Define to chown, for convenience. (struct dir_attr): Cache the entire struct stat of the directory, rather than just its mode, so that we needn't stat the directory twice (which can lead to races). (re_protect): Don't use XSTAT as that's not appropriate in this context (symlinks should be followed here). Instead, use the cached stat value. (make_dir_parents_private): Save dir's entire struct stat, not just its mode. * tests/cp/cp-parents: Add test to check against bug with cp --parents and symlinks. --- src/install.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/install.c') diff --git a/src/install.c b/src/install.c index dc7ff0141..39d514957 100644 --- a/src/install.c +++ b/src/install.c @@ -62,6 +62,10 @@ static bool use_default_selinux_context = true; # define endpwent() ((void) 0) #endif +#if ! HAVE_LCHOWN +# define lchown(name, uid, gid) chown (name, uid, gid) +#endif + /* Initial number of entries in each hash table entry's table of inodes. */ #define INITIAL_HASH_MODULE 100 @@ -606,7 +610,7 @@ change_attributes (char const *name) want to know. */ if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1) - && chown (name, owner_id, group_id) != 0) + && lchown (name, owner_id, group_id) != 0) error (0, errno, _("cannot change ownership of %s"), quote (name)); else if (chmod (name, mode) != 0) error (0, errno, _("cannot change permissions of %s"), quote (name)); -- cgit v1.2.3-54-g00ecf