Subject: [automake patch] use --hard-dereference with GNU Tar (was: dist tarball contains hardlinks)

From: Dimitrios Apostolou <[email-masked]>
Date: Mon, 16 Mar 2015 16:46:24 +0100 (CET)

On Mon, 16 Mar 2015, Dimitrios Apostolou wrote:
> On Fri, 13 Mar 2015, Dimitrios Apostolou wrote:
>> 
>> I believe my only choice at this point is to forbid "make dist" if tar is 
>> detected to be old (less than 1.29), and keep doing --hard-dereference. I 
>> open to new ideas though. :-)
>
> The attached patch solves the problem in a more elegant manner IMHO, so I 
> plan to include this modified tar.m4 in my project.
>
> Review is welcome, and feel free to include to upstream automake.

Please ignore the previous patch. The one attached here has prettier 
printing and also works with GNU tar versions that don't return 64 in case 
of unrecognized option.

Thanks,
Dimitris
From 62ff854174fa73fc5a26796b8857cd3c390c3959 Mon Sep 17 00:00:00 2001
From: Dimitrios Apostolou <[email-masked]>
Date: Mon, 16 Mar 2015 13:09:06 +0100
Subject: [PATCH 1/1] GNU Tar now uses --hard-dereference when possible

Historically "make dist" tries to store only files inside the tarball,
avoiding all symlinks/hardlinks in order to bypass limitations of the
tar format (for example the "ustar" format allows only 100 characters
filenames for symlinks). For that reason -o (i.e. --dereference) has
been passed to the tar command.

However GNU Tar changed its behaviour since v1.24 and stores symlinks as
hardlinks if --dereference is passed. Thus we now need to pass
--hard-dereference to make sure no links are stored in the
tarball. Unfortunately this option is available since GNU tar v1.28,
which means that for versions 1.24-1.28 "make dist" will create tarballs
containing hardlinks, with all the limitations of the respective format
(see [1]).

[1] http://www.gnu.org/software/tar/manual/html_section/tar_68.html
---
 m4/tar.m4 | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/m4/tar.m4 b/m4/tar.m4
index d8054cb..c7fc521 100644
--- a/m4/tar.m4
+++ b/m4/tar.m4
@@ -72,18 +72,27 @@ m4_if([$1], [v7],
   _am_tools=${am_cv_prog_tar_$1-$_am_tools}
 
   for _am_tool in $_am_tools; do
     case $_am_tool in
     gnutar)
       for _am_tar in tar gnutar gtar; do
         AM_RUN_LOG([$_am_tar --version]) && break
       done
-      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
-      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      AM_RUN_LOG([$_am_tar --hard-dereference  2>&1 | grep 'unrecognized option'])
+      # Check if --hard-dereference is supported by this version of GNU Tar
+      if test "$ac_status" -eq 0; then
+        _am_gnutar_hard_dereference=false
+        am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+        am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      else
+        _am_gnutar_hard_dereference=true
+        am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) --hard-dereference -chf - "'"$$tardir"'
+        am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) --hard-dereference -chf - "'"$tardir"'
+      fi
       am__untar="$_am_tar -xf -"
       ;;
     plaintar)
       # Must skip GNU tar: if it does not support --format= it doesn't create
       # ustar tarball either.
       (tar --version) >/dev/null 2>&1 && continue
       am__tar='tar chf - "$$tardir"'
       am__tar_='tar chf - "$tardir"'
@@ -122,11 +131,21 @@ m4_if([$1], [v7],
       grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
     fi
   done
   rm -rf conftest.dir
 
   AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
   AC_MSG_RESULT([$am_cv_prog_tar_$1])])
 
+  if test $_am_tool = gnutar; then
+    # We've checked already, so we're just printing here
+    AC_MSG_CHECKING([if GNU tar supports --hard-dereference])
+    if test x$_am_gnutar_hard_dereference = xtrue; then
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+    fi
+  fi
+
 AC_SUBST([am__tar])
 AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
-- 
1.9.1