Subject: Re: bug#15173: [PATCH] cp: with --link always use linkat() if available

From: Pádraig Brady <[email-masked]>
Date: Thu, 12 Dec 2013 23:11:36 +0000

So while the above patch is probably correct, it's slightly risky
at this stage before a release.  Also the benefits are minimal as
the existing symlink to symlink emulation should be fine on the mentioned systems.

Therefore I'll go with the attached patch which fixes the test to run
on all platforms. The test failed on freebsd, aix and solaris previously,
and I've confirmed it now passes on all those.

cheers,
Pádraig.

>From 4efea60dbee1fef6aab1e9385813beb7d92f8178 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email-masked]>
Date: Thu, 12 Dec 2013 22:43:05 +0000
Subject: [PATCH] tests: restrict cp --link inode comparisons to compatible
 systems

* tests/cp/link-deref.sh: On systems were cp can't determine if
gnulib linkat() emulation might create a symlink instead of a hardlink
to a symlink, copy.c will create a symlink to the symlink so that
it has more control over its metadata.  Also even if the system
supports this operation, the particular file system under test may not.
So avoid the hardlinked symlink verification in these cases.
This fixes a false failure on aix, solaris and freebsd.
---
 tests/cp/link-deref.sh |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/tests/cp/link-deref.sh b/tests/cp/link-deref.sh
index c12dfc8..89f7a36 100755
--- a/tests/cp/link-deref.sh
+++ b/tests/cp/link-deref.sh
@@ -19,6 +19,18 @@
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ cp
 
+if grep '^#define HAVE_LINKAT 1' "$CONFIG_HEADER" > /dev/null \
+   && grep '^#define LINK_FOLLOWS_SYMLINKS 0' "$CONFIG_HEADER" > /dev/null; then
+  # With this config (which is the case on GNU/Linux) cp will attempt to
+  # linkat() to hardlink a symlink.  So now see if the current file system
+  # supports this operation.
+  ln -s testtarget test_sl || framework_failure_
+  ln -P test_sl test_hl_sl || framework_failure_
+  ino_sl="$(stat -c '%i' test_sl)" || framework_failure_
+  ino_hl="$(stat -c '%i' test_hl_sl)" || framework_failure_
+  test "$ino_sl" = "$ino_hl" && can_hardlink_to_symlink=1
+fi
+
 mkdir dir              || framework_failure_
 : > file               || framework_failure_
 ln -s dir     dirlink  || framework_failure_
@@ -39,6 +51,10 @@ for src in dirlink filelink danglink; do
   typ_tgt="$(stat -c '%F' $tgt 2>/dev/null)" || typ_tgt=
 
   for o in '' -L -H -P; do
+
+    # Skip the -P case where we don't or can't hardlink symlinks
+    ! test "$can_hardlink_to_symlink" && test "$o" = '-P' && continue
+
     for r in '' -R; do
 
       command="cp --link $o $r $src dst"
-- 
1.7.7.6