summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2006-06-03 09:04:22 +0000
committerJim Meyering <jim@meyering.net>2006-06-03 09:04:22 +0000
commit4c7979f7c249606c0d6b73fd01b92b0825d83741 (patch)
tree8ddc8281638f90c238886684d1248e4d8649ecc2 /src
parent6293c4ae503c59411e8f2f66e91149a47829fbd9 (diff)
downloadcoreutils-4c7979f7c249606c0d6b73fd01b92b0825d83741.tar.xz
Make `cp --link --no-dereference' work also on systems where the
link system call cannot create a hard link to a symbolic link. (copy_internal) [LINK_FOLLOWS_SYMLINKS]: Don't use the link syscall on a symlink when it would do the wrong thing. Based on the patch by Aurelien Jarno: <http://bugs.debian.org/329451>
Diffstat (limited to 'src')
-rw-r--r--src/copy.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/src/copy.c b/src/copy.c
index a6f6ec54e..a6ea3e6b6 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -1594,7 +1594,22 @@ copy_internal (char const *src_name, char const *dst_name,
}
}
#endif
- else if (x->hard_link)
+
+ else if (x->hard_link
+#ifdef LINK_FOLLOWS_SYMLINKS
+ /* A POSIX-conforming link syscall dereferences a symlink, yet cp,
+ invoked with `--link --no-dereference', should not. Thus, with
+ a POSIX-conforming link system call, we can't use link() here,
+ since that would create a hard link to the referent (effectively
+ dereferencing the symlink), rather than to the symlink itself.
+ We can approximate the desired behavior by skipping this hard-link
+ creating block and instead copying the symlink, via the `S_ISLNK'-
+ copying code below.
+ When link operates on the symlinks themselves, we use this block
+ and just call link(). */
+ && !(S_ISLNK (src_mode) && x->dereference == DEREF_NEVER)
+#endif
+ )
{
preserve_metadata = false;
if (link (src_name, dst_name))