]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
Make `cp --link --no-dereference' work also on systems where the
authorJim Meyering <jim@meyering.net>
Sat, 3 Jun 2006 09:04:22 +0000 (09:04 +0000)
committerJim Meyering <jim@meyering.net>
Sat, 3 Jun 2006 09:04:22 +0000 (09:04 +0000)
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>

src/copy.c

index a6f6ec54ea6a871888373e5f02e0a369aa0b5405..a6ea3e6b6a768a94c083448cf992975860d17b5d 100644 (file)
@@ -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))