changeset 10107:0f973047765d

Tests for the 'copy-file' module.
author Bruno Haible <bruno@clisp.org>
date Thu, 22 May 2008 19:23:54 +0200
parents 82c8ae7cd046
children bf329a08180c
files ChangeLog modules/copy-file-tests tests/test-copy-file-sameacls.c tests/test-copy-file.c tests/test-copy-file.sh
diffstat 5 files changed, 1089 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2008-05-22  Bruno Haible  <bruno@clisp.org>
+
+	* modules/copy-file-tests: New file.
+	* tests/test-copy-file.sh: New file.
+	* tests/test-copy-file.c: New file.
+	* tests/test-copy-file-sameacls.c: New file.
+
 2008-05-22  Eric Blake  <ebb9@byu.net>
 
 	Avoid gcc warning.
new file mode 100644
--- /dev/null
+++ b/modules/copy-file-tests
@@ -0,0 +1,33 @@
+Files:
+tests/test-copy-file.sh
+tests/test-copy-file.c
+tests/test-copy-file-sameacls.c
+
+Depends-on:
+acl
+progname
+read-file
+xalloc
+
+configure.ac:
+AC_REQUIRE([gl_FUNC_ACL])
+save_LIBS="$LIBS"
+LIBS="$LIB_ACL $LIBS"
+dnl Test for functions present on Linux, FreeBSD, MacOS X, IRIX, Tru64, Cygwin.
+AC_CHECK_FUNCS([acl_get_file])
+dnl Test for functions present on Solaris.
+AC_CHECK_FUNCS([acl])
+dnl Test for functions present on HP-UX.
+AC_CHECK_FUNCS([getacl])
+dnl Test for functions present on AIX.
+AC_CHECK_FUNCS([aclx_get])
+dnl Test for functions present on older AIX.
+AC_CHECK_FUNCS([statacl])
+LIBS="$save_LIBS"
+
+Makefile.am:
+TESTS += test-copy-file.sh
+TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@'
+check_PROGRAMS += test-copy-file test-copy-file-sameacls
+test_copy_file_LDADD = $(LDADD) $(LIB_ACL) @LIBINTL@
+test_copy_file_sameacls_LDADD = $(LDADD) $(LIB_ACL) @LIBINTL@
new file mode 100644
--- /dev/null
+++ b/tests/test-copy-file-sameacls.c
@@ -0,0 +1,508 @@
+/* Test whether two files have the same ACLs.
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2008.  */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#if HAVE_ACL_GET_FILE || HAVE_ACL || HAVE_ACLX_GET || HAVE_STATACL
+# include <sys/types.h>
+# include <sys/acl.h>
+#endif
+
+#include "read-file.h"
+#include "xalloc.h"
+
+#define ASSERT(expr) \
+  do									     \
+    {									     \
+      if (!(expr))							     \
+        {								     \
+          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+          fflush (stderr);						     \
+          abort ();							     \
+        }								     \
+    }									     \
+  while (0)
+
+int
+main (int argc, char *argv[])
+{
+  const char *file1;
+  const char *file2;
+
+  ASSERT (argc == 3);
+
+  file1 = argv[1];
+  file2 = argv[2];
+
+  /* Compare the contents of the two files.  */
+  {
+    size_t size1;
+    char *contents1;
+    size_t size2;
+    char *contents2;
+
+    contents1 = read_file (file1, &size1);
+    if (contents1 == NULL)
+      {
+	fprintf (stderr, "error reading file %s: errno = %d\n", file1, errno);
+	fflush (stderr);
+	abort ();
+      }
+    contents2 = read_file (file2, &size2);
+    if (contents2 == NULL)
+      {
+	fprintf (stderr, "error reading file %s: errno = %d\n", file2, errno);
+	fflush (stderr);
+	abort ();
+      }
+
+    if (size2 != size1)
+      {
+	fprintf (stderr, "files %s and %s have different sizes\n",
+		 file1, file2);
+	fflush (stderr);
+	abort ();
+      }
+    if (memcmp (contents1, contents2, size1) != 0)
+      {
+	fprintf (stderr, "files %s and %s have different contents\n",
+		 file1, file2);
+	fflush (stderr);
+	abort ();
+      }
+  }
+
+  /* Compare the access permissions of the two files, including ACLs.  */
+  {
+    struct stat statbuf1;
+    struct stat statbuf2;
+
+    if (stat (file1, &statbuf1) < 0)
+      {
+	fprintf (stderr, "error accessing file %s: errno = %d\n", file1, errno);
+	fflush (stderr);
+	abort ();
+      }
+    if (stat (file2, &statbuf2) < 0)
+      {
+	fprintf (stderr, "error accessing file %s: errno = %d\n", file2, errno);
+	fflush (stderr);
+	abort ();
+      }
+    if (statbuf1.st_mode != statbuf2.st_mode)
+      {
+	fprintf (stderr, "files %s and %s have different access modes: %03o and %03o\n",
+		 file1, file2,
+		(unsigned int) statbuf1.st_mode, (unsigned int) statbuf2.st_mode);
+	return 1;
+      }
+  }
+  {
+#if HAVE_ACL_GET_FILE /* Linux, FreeBSD, MacOS X, IRIX, Tru64, Cygwin */
+    acl_t acl1;
+    char *text1;
+    int errno1;
+    acl_t acl2;
+    char *text2;
+    int errno2;
+
+    acl1 = acl_get_file (file1, ACL_TYPE_ACCESS);
+    if (acl1 == (acl_t)NULL)
+      {
+	text1 = NULL;
+	errno1 = errno;
+      }
+    else
+      {
+	text1 = acl_to_text (acl1, NULL);
+	if (text1 == NULL)
+	  errno1 = errno;
+	else
+	  errno1 = 0;
+      }
+    acl2 = acl_get_file (file2, ACL_TYPE_ACCESS);
+    if (acl2 == (acl_t)NULL)
+      {
+	text2 = NULL;
+	errno2 = errno;
+      }
+    else
+      {
+	text2 = acl_to_text (acl2, NULL);
+	if (text2 == NULL)
+	  errno2 = errno;
+	else
+	  errno2 = 0;
+      }
+
+    if (acl1 != (acl_t)NULL)
+      {
+	if (acl2 != (acl_t)NULL)
+	  {
+	    if (text1 != NULL)
+	      {
+		if (text2 != NULL)
+		  {
+		    if (strcmp (text1, text2) != 0)
+		      {
+			fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
+				 file1, file2, text1, text2);
+			return 1;
+		      }
+		  }
+		else
+		  {
+		    fprintf (stderr, "file %s has a valid ACL, but file %s has an invalid ACL\n",
+			     file1, file2);
+		    return 1;
+		  }
+	      }
+	    else
+	      {
+		if (text2 != NULL)
+		  {
+		    fprintf (stderr, "file %s has an invalid ACL, but file %s has a valid ACL\n",
+			     file1, file2);
+		    return 1;
+		  }
+		else
+		  {
+		    if (errno1 != errno2)
+		      {
+			fprintf (stderr, "files %s and %s have differently invalid ACLs, errno = %d vs. %d\n",
+				 file1, file2, errno1, errno2);
+			return 1;
+		      }
+		  }
+	      }
+	  }
+	else
+	  {
+	    fprintf (stderr, "file %s has an ACL, but file %s has no ACL\n",
+		     file1, file2);
+	    return 1;
+	  }
+      }
+    else
+      {
+	if (acl2 != (acl_t)NULL)
+	  {
+	    fprintf (stderr, "file %s has no ACL, but file %s has an ACL\n",
+		     file1, file2);
+	    return 1;
+	  }
+      }
+#elif HAVE_ACL && defined GETACL /* Solaris, not HP-UX */
+  int count1;
+  int count2;
+
+  count1 = acl (file1, GETACLCNT, 0, NULL);
+  count2 = acl (file2, GETACLCNT, 0, NULL);
+
+  if (count1 != count2)
+    {
+      if (count1 < 0)
+	{
+	  fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
+	  fflush (stderr);
+	  abort ();
+	}
+      if (count2 < 0)
+	{
+	  fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
+	  fflush (stderr);
+	  abort ();
+	}
+      fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
+	       file1, file2, count1, count2);
+      return 1;
+    }
+  else
+    {
+      aclent_t *entries1 = XNMALLOC (count1, aclent_t);
+      aclent_t *entries2 = XNMALLOC (count2, aclent_t);
+      int i;
+
+      if (acl (file1, GETACL, count1, entries1) < count1)
+	{
+	  fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
+	  fflush (stderr);
+	  abort ();
+	}
+      if (acl (file2, GETACL, count2, entries2) < count1)
+	{
+	  fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
+	  fflush (stderr);
+	  abort ();
+	}
+      for (i = 0; i < count1; i++)
+	{
+	  if (entries1[i].a_type != entries2[i].a_type)
+	    {
+	      fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
+		       file1, file2, i, entries1[i].a_type, entries2[i].a_type);
+	      return 1;
+	    }
+	  if (entries1[i].a_id != entries2[i].a_id)
+	    {
+	      fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
+		       file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
+	      return 1;
+	    }
+	  if (entries1[i].a_perm != entries2[i].a_perm)
+	    {
+	      fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
+		       file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
+	      return 1;
+	    }
+	}
+    }
+# ifdef ACE_GETACL
+  count1 = acl (file1, ACE_GETACLCNT, 0, NULL);
+  count2 = acl (file2, ACE_GETACLCNT, 0, NULL);
+  if (count1 != count2)
+    {
+      if (count1 < 0)
+	{
+	  fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file1);
+	  fflush (stderr);
+	  abort ();
+	}
+      if (count2 < 0)
+	{
+	  fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file2);
+	  fflush (stderr);
+	  abort ();
+	}
+      fprintf (stderr, "files %s and %s have different number of ACE-ACLs: %d and %d\n",
+	       file1, file2, count1, count2);
+      return 1;
+    }
+  else if (count1 > 0)
+    {
+      ace_t *entries1 = XNMALLOC (count1, ace_t);
+      ace_t *entries2 = XNMALLOC (count2, ace_t);
+      int i;
+
+      if (acl (file1, ACE_GETACL, count1, entries1) < count1)
+	{
+	  fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file1);
+	  fflush (stderr);
+	  abort ();
+	}
+      if (acl (file2, ACE_GETACL, count2, entries2) < count1)
+	{
+	  fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file2);
+	  fflush (stderr);
+	  abort ();
+	}
+      for (i = 0; i < count1; i++)
+	{
+	  if (entries1[i].a_type != entries2[i].a_type)
+	    {
+	      fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different types %d and %d\n",
+		       file1, file2, i, entries1[i].a_type, entries2[i].a_type);
+	      return 1;
+	    }
+	  if (entries1[i].a_who != entries2[i].a_who)
+	    {
+	      fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different ids %d and %d\n",
+		       file1, file2, i, (int)entries1[i].a_who, (int)entries2[i].a_who);
+	      return 1;
+	    }
+	  if (entries1[i].a_access_mask != entries2[i].a_access_mask)
+	    {
+	      fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different access masks %03o and %03o\n",
+		       file1, file2, i, (unsigned int) entries1[i].a_access_mask, (unsigned int) entries2[i].a_access_mask);
+	      return 1;
+	    }
+	  if (entries1[i].a_flags != entries2[i].a_flags)
+	    {
+	      fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different flags 0x%x and 0x%x\n",
+		       file1, file2, i, (unsigned int) entries1[i].a_flags, (unsigned int) entries2[i].a_flags);
+	      return 1;
+	    }
+	}
+    }
+# endif
+#elif HAVE_GETACL /* HP-UX */
+  int count1;
+  int count2;
+
+  count1 = getacl (file1, 0, NULL);
+  count2 = getacl (file2, 0, NULL);
+
+  if (count1 != count2)
+    {
+      if (count1 < 0)
+	{
+	  fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
+	  fflush (stderr);
+	  abort ();
+	}
+      if (count2 < 0)
+	{
+	  fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
+	  fflush (stderr);
+	  abort ();
+	}
+      fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
+	       file1, file2, count1, count2);
+      return 1;
+    }
+  else
+    {
+      struct acl_entry *entries1 = XNMALLOC (count1, struct acl_entry);
+      struct acl_entry *entries2 = XNMALLOC (count2, struct acl_entry);
+      int i;
+
+      if (getacl (file1, count1, entries1) < count1)
+	{
+	  fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
+	  fflush (stderr);
+	  abort ();
+	}
+      if (getacl (file2, count2, entries2) < count1)
+	{
+	  fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
+	  fflush (stderr);
+	  abort ();
+	}
+      for (i = 0; i < count1; i++)
+	{
+	  if (entries1[i].uid != entries2[i].uid)
+	    {
+	      fprintf (stderr, "files %s and %s: different ACL entry #%d: different uids %d and %d\n",
+		       file1, file2, i, (int)entries1[i].uid, (int)entries2[i].uid);
+	      return 1;
+	    }
+	  if (entries1[i].gid != entries2[i].gid)
+	    {
+	      fprintf (stderr, "files %s and %s: different ACL entry #%d: different gids %d and %d\n",
+		       file1, file2, i, (int)entries1[i].gid, (int)entries2[i].gid);
+	      return 1;
+	    }
+	  if (entries1[i].mode != entries2[i].mode)
+	    {
+	      fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
+		       file1, file2, i, (unsigned int) entries1[i].mode, (unsigned int) entries2[i].mode);
+	      return 1;
+	    }
+	}
+    }
+#elif HAVE_ACLX_GET /* AIX */
+  acl_type_t type1;
+  char acl1[1000];
+  size_t aclsize1 = sizeof (acl1);
+  mode_t mode1;
+  char text1[1000];
+  acl_type_t type2;
+  char acl2[1000];
+  size_t aclsize2 = sizeof (acl2);
+  mode_t mode2;
+  char text2[1000];
+
+  if (aclx_get (file1, 0, &type1, acl1, &aclsize1, &mode1) < 0)
+    {
+      fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
+      fflush (stderr);
+      abort ();
+    }
+  if (aclx_printStr (text1, sizeof (text1), acl1, aclsize1, type1, file1, 0) < 0)
+    {
+      fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file1);
+      fflush (stderr);
+      abort ();
+    }
+
+  if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0)
+    {
+      fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
+      fflush (stderr);
+      abort ();
+    }
+  if (aclx_printStr (text2, sizeof (text2), acl2, aclsize2, type2, file2, 0) < 0)
+    {
+      fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file2);
+      fflush (stderr);
+      abort ();
+    }
+
+  if (strcmp (text1, text2) != 0)
+    {
+      fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
+	       file1, file2, text1, text2);
+      return 1;
+    }
+#elif HAVE_STATACL /* older AIX */
+  union { struct acl a; char room[4096]; } acl1;
+  union { struct acl a; char room[4096]; } acl2;
+  unsigned int i;
+
+  if (statacl (file1, STX_NORMAL, &acl1.a, sizeof (acl1)) < 0)
+    {
+      fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
+      fflush (stderr);
+      abort ();
+    }
+  if (statacl (file2, STX_NORMAL, &acl2.a, sizeof (acl2)) < 0)
+    {
+      fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
+      fflush (stderr);
+      abort ();
+    }
+
+  if (acl1.a.acl_len != acl2.a.acl_len)
+    {
+      fprintf (stderr, "files %s and %s have different ACL lengths: %u and %u\n",
+	       file1, file2, acl1.a.acl_len, acl2.a.acl_len);
+      return 1;
+    }
+  if (acl1.a.acl_mode != acl2.a.acl_mode)
+    {
+      fprintf (stderr, "files %s and %s have different ACL modes: %03o and %03o\n",
+	       file1, file2, acl1.a.acl_mode, acl2.a.acl_mode);
+      return 1;
+    }
+  if (acl1.a.u_access != acl2.a.u_access
+      || acl1.a.g_access != acl2.a.g_access
+      || acl1.a.o_access != acl2.a.o_access)
+    {
+      fprintf (stderr, "files %s and %s have different ACL access masks: %03o %03o %03o and %03o %03o %03o\n",
+	       file1, file2,
+	       acl1.a.u_access, acl1.a.g_access, acl1.a.o_access,
+	       acl2.a.u_access, acl2.a.g_access, acl2.a.o_access);
+      return 1;
+    }
+  if (memcmp (acl1.a.acl_ext, acl2.a.acl_ext, acl1.a.acl_len) != 0)
+    {
+      fprintf (stderr, "files %s and %s have different ACL entries\n",
+	       file1, file2);
+      return 1;
+    }
+#endif
+  }
+
+  return 0;
+}
new file mode 100644
--- /dev/null
+++ b/tests/test-copy-file.c
@@ -0,0 +1,56 @@
+/* Test of copying of files.
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2008.  */
+
+#include <config.h>
+
+#include "copy-file.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "progname.h"
+
+#define ASSERT(expr) \
+  do									     \
+    {									     \
+      if (!(expr))							     \
+        {								     \
+          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+          fflush (stderr);						     \
+          abort ();							     \
+        }								     \
+    }									     \
+  while (0)
+
+int
+main (int argc, char *argv[])
+{
+  const char *file1;
+  const char *file2;
+
+  set_program_name (argv[0]);
+
+  ASSERT (argc == 3);
+
+  file1 = argv[1];
+  file2 = argv[2];
+
+  copy_file_preserving (file1, file2);
+
+  return 0;
+}
new file mode 100755
--- /dev/null
+++ b/tests/test-copy-file.sh
@@ -0,0 +1,485 @@
+#!/bin/sh
+
+# Show all commands when run with environment variable VERBOSE=yes.
+test -z "$VERBOSE" || set -x
+
+# func_tmpdir
+# creates a temporary directory.
+# Sets variable
+# - tmp             pathname of freshly created temporary directory
+func_tmpdir ()
+{
+  # Use the environment variable TMPDIR, falling back to /tmp. This allows
+  # users to specify a different temporary directory, for example, if their
+  # /tmp is filled up or too small.
+  : ${TMPDIR=/tmp}
+  {
+    # Use the mktemp program if available. If not available, hide the error
+    # message.
+    tmp=`(umask 077 && mktemp -d "$TMPDIR/glXXXXXX") 2>/dev/null` &&
+    test -n "$tmp" && test -d "$tmp"
+  } ||
+  {
+    # Use a simple mkdir command. It is guaranteed to fail if the directory
+    # already exists.  $RANDOM is bash specific and expands to empty in shells
+    # other than bash, ksh and zsh.  Its use does not increase security;
+    # rather, it minimizes the probability of failure in a very cluttered /tmp
+    # directory.
+    tmp=$TMPDIR/gl$$-$RANDOM
+    (umask 077 && mkdir "$tmp")
+  } ||
+  {
+    echo "$0: cannot create a temporary directory in $TMPDIR" >&2
+    exit 1
+  }
+}
+
+func_tmpdir
+builddir=`pwd`
+cd "$builddir" ||
+  {
+    echo "$0: cannot determine build directory (unreadable parent dir?)" >&2
+    exit 1
+  }
+# Switch to a temporary directory, to increase the likelihood that ACLs are
+# supported on the current file system. (/tmp is usually locally mounted,
+# whereas the build dir is sometimes NFS-mounted.)
+( cd "$tmp"
+
+  # Prepare tmpfile0.
+  rm -f tmpfile[0-9] tmpaclout[12]
+  echo "Simple contents" > tmpfile0
+  chmod 600 tmpfile0
+
+  # Classification of the platform according to the programs available for
+  # manipulating ACLs.
+  # Possible values are:
+  #   linux, cygwin, freebsd, solaris, hpux, osf1, aix, macosx, irix, none.
+  # TODO: Support also native Win32 platforms (mingw).
+  acl_flavor=none
+  if (getfacl tmpfile0 >/dev/null) 2>/dev/null; then
+    # Platforms with the getfacl and setfacl programs.
+    # Linux, FreeBSD, Solaris, Cygwin.
+    if (setfacl --help >/dev/null) 2>/dev/null; then
+      # Linux, Cygwin.
+      if (LC_ALL=C setfacl --help | grep ' --set-file' >/dev/null) 2>/dev/null; then
+        # Linux.
+        acl_flavor=linux
+      else
+        acl_flavor=cygwin
+      fi
+    else
+      # FreeBSD, Solaris.
+      if (LC_ALL=C setfacl 2>&1 | grep '\-x entries' >/dev/null) 2>/dev/null; then
+        # FreeBSD.
+        acl_flavor=freebsd
+      else
+        # Solaris.
+        acl_flavor=solaris
+      fi
+    fi
+  else
+    if (lsacl tmpfile0 >/dev/null) 2>/dev/null; then
+      # Platforms with the lsacl and chacl programs.
+      # HP-UX, sometimes also IRIX.
+      acl_flavor=hpux
+    else
+      if (getacl tmpfile0 >/dev/null) 2>/dev/null; then
+        # Tru64.
+        acl_flavor=osf1
+      else
+        if (aclget tmpfile0 >/dev/null) 2>/dev/null; then
+          # AIX.
+          acl_flavor=aix
+        else
+          if (fsaclctl -v >/dev/null) 2>/dev/null; then
+            # MacOS X.
+            acl_flavor=macosx
+          else
+            if test -f /sbin/chacl; then
+              # IRIX.
+              acl_flavor=irix
+            fi
+          fi
+        fi
+      fi
+    fi
+  fi
+
+  # Define a function to test for the same ACLs, from the point of view of
+  # the programs.
+  # func_test_same_acls file1 file2
+  case $acl_flavor in
+    linux | cygwin | freebsd | solaris)
+      func_test_same_acls ()
+      {
+        getfacl "$1" | sed -e "s/$1/FILENAME/g" > tmpaclout1
+        getfacl "$2" | sed -e "s/$2/FILENAME/g" > tmpaclout2
+        cmp tmpaclout1 tmpaclout2 > /dev/null
+      }
+      ;;
+    hpux)
+      func_test_same_acls ()
+      {
+        lsacl "$1" | sed -e "s/$1/FILENAME/g" > tmpaclout1
+        lsacl "$2" | sed -e "s/$2/FILENAME/g" > tmpaclout2
+        cmp tmpaclout1 tmpaclout2 > /dev/null
+      }
+      ;;
+    osf1)
+      func_test_same_acls ()
+      {
+        getacl "$1" | sed -e "s/$1/FILENAME/g" > tmpaclout1
+        getacl "$2" | sed -e "s/$2/FILENAME/g" > tmpaclout2
+        cmp tmpaclout1 tmpaclout2 > /dev/null
+      }
+      ;;
+    aix)
+      func_test_same_acls ()
+      {
+        aclget "$1" > tmpaclout1
+        aclget "$2" > tmpaclout2
+        cmp tmpaclout1 tmpaclout2 > /dev/null
+      }
+      ;;
+    macosx)
+      func_test_same_acls ()
+      {
+        /bin/ls -le "$1" | sed -e "s/$1/FILENAME/g" > tmpaclout1
+        /bin/ls -le "$2" | sed -e "s/$2/FILENAME/g" > tmpaclout2
+        cmp tmpaclout1 tmpaclout2 > /dev/null
+      }
+      ;;
+    irix)
+      func_test_same_acls ()
+      {
+        /bin/ls -lD "$1" | sed -e "s/$1/FILENAME/g" > tmpaclout1
+        /bin/ls -lD "$2" | sed -e "s/$2/FILENAME/g" > tmpaclout2
+        cmp tmpaclout1 tmpaclout2 > /dev/null
+      }
+      ;;
+    none)
+      func_test_same_acls ()
+      {
+        :
+      }
+      ;;
+  esac
+
+  # func_test_copy file1 file2
+  # copies file1 to file2 and verifies the permissions and ACLs are the same
+  # on both.
+  func_test_copy ()
+  {
+    "$builddir"/test-copy-file${EXEEXT}          "$1" "$2" || exit 1
+    "$builddir"/test-copy-file-sameacls${EXEEXT} "$1" "$2" || exit 1
+    func_test_same_acls                          "$1" "$2" || exit 1
+  }
+
+  func_test_copy tmpfile0 tmpfile1
+
+  if test $acl_flavor != none; then
+    # Use a user and group id different from the current one, to avoid
+    # redundant/ambiguous ACLs.
+    myuid=`id -u`
+    mygid=`id -g`
+    auid=1
+    if test "$auid" = "$myuid"; then auid=2; fi
+    agid=1
+    if test "$agid" = "$mygid"; then agid=2; fi
+
+    case $acl_flavor in
+      linux | cygwin | freebsd | solaris)
+
+        # Set an ACL for a user.
+        setfacl -m user:$auid:1 tmpfile0
+
+        func_test_copy tmpfile0 tmpfile2
+
+        # Set an ACL for a group.
+        setfacl -m group:$agid:4 tmpfile0
+
+        func_test_copy tmpfile0 tmpfile3
+
+        # Set an ACL for other.
+        case $acl_flavor in
+          freebsd) setfacl -m other::4 tmpfile0 ;;
+          solaris) chmod o+r tmpfile0 ;;
+          *)       setfacl -m other:4 tmpfile0 ;;
+        esac
+
+        func_test_copy tmpfile0 tmpfile4
+
+        # Remove the ACL for the user.
+        case $acl_flavor in
+          linux)   setfacl -x user:$auid tmpfile0 ;;
+          freebsd) setfacl -x user:$auid:1 tmpfile0 ;;
+          *)       setfacl -d user:$auid:1 tmpfile0 ;;
+        esac
+
+        func_test_copy tmpfile0 tmpfile5
+
+        # Remove the ACL for other.
+        case $acl_flavor in
+          linux)   ;; # impossible
+          freebsd) setfacl -x other::4 tmpfile0 ;;
+          *)       setfacl -d other:4 tmpfile0 ;;
+        esac
+
+        func_test_copy tmpfile0 tmpfile6
+
+        # Remove the ACL for the group.
+        case $acl_flavor in
+          linux)   setfacl -x group:$agid tmpfile0 ;;
+          freebsd) setfacl -x group:$agid:4 tmpfile0 ;;
+          *)       setfacl -d group:$agid:4 tmpfile0 ;;
+        esac
+
+        func_test_copy tmpfile0 tmpfile7
+
+        # Delete all optional ACLs.
+        case $acl_flavor in
+          linux | freebsd)
+            setfacl -m user:$auid:1 tmpfile0
+            setfacl -b tmpfile0
+            ;;
+          *)
+            setfacl -s user::6,group::0,other:0 tmpfile0 ;;
+        esac
+
+        func_test_copy tmpfile0 tmpfile8
+
+        # Copy ACLs from a file that has no ACLs.
+        echo > tmpfile9
+        chmod a+x tmpfile9
+        case $acl_flavor in
+          linux)   getfacl tmpfile9 | setfacl --set-file=- tmpfile0 ;;
+          freebsd) ;;
+          *)       getfacl tmpfile9 | setfacl -f - tmpfile0 ;;
+        esac
+        rm -f tmpfile9
+
+        func_test_copy tmpfile0 tmpfile9
+
+        ;;
+
+      hpux)
+
+        # Set an ACL for a user.
+        orig=`lsacl tmpfile0 | sed -e 's/ tmpfile0$//'`
+        chacl -r "${orig}($auid.%,--x)" tmpfile0
+
+        func_test_copy tmpfile0 tmpfile2
+
+        # Set an ACL for a group.
+        orig=`lsacl tmpfile0 | sed -e 's/ tmpfile0$//'`
+        chacl -r "${orig}(%.$agid,r--)" tmpfile0
+
+        func_test_copy tmpfile0 tmpfile3
+
+        # Set an ACL for other.
+        orig=`lsacl tmpfile0 | sed -e 's/ tmpfile0$//'`
+        chacl -r "${orig}(%.%,r--)" tmpfile0
+
+        func_test_copy tmpfile0 tmpfile4
+
+        # Remove the ACL for the user.
+        chacl -d "($auid.%,--x)" tmpfile0
+
+        func_test_copy tmpfile0 tmpfile5
+
+        # Remove the ACL for the group.
+        chacl -d "(%.$agid,r--)" tmpfile0
+
+        func_test_copy tmpfile0 tmpfile6
+
+        # Delete all optional ACLs.
+        chacl -z tmpfile0
+
+        func_test_copy tmpfile0 tmpfile8
+
+        # Copy ACLs from a file that has no ACLs.
+        echo > tmpfile9
+        chmod a+x tmpfile9
+        orig=`lsacl tmpfile9 | sed -e 's/ tmpfile9$//'`
+        rm -f tmpfile9
+        chacl -r "${orig}" tmpfile0
+
+        func_test_copy tmpfile0 tmpfile9
+
+        ;;
+
+      osf1)
+
+        # Set an ACL for a user.
+        setacl -u user:$auid:1 tmpfile0
+
+        func_test_copy tmpfile0 tmpfile2
+
+        # Set an ACL for a group.
+        setacl -u group:$agid:4 tmpfile0
+
+        func_test_copy tmpfile0 tmpfile3
+
+        # Set an ACL for other.
+        setacl -u other:4 tmpfile0
+
+        func_test_copy tmpfile0 tmpfile4
+
+        # Remove the ACL for the user.
+        setacl -x user:$auid:1 tmpfile0
+
+        func_test_copy tmpfile0 tmpfile5
+
+        # Remove the ACL for other.
+        setacl -x other:4 tmpfile0
+
+        func_test_copy tmpfile0 tmpfile6
+
+        # Remove the ACL for the group.
+        setacl -x group:$agid:4 tmpfile0
+
+        func_test_copy tmpfile0 tmpfile7
+
+        # Delete all optional ACLs.
+        setacl -u user:$auid:1 tmpfile0
+        setacl -b tmpfile0
+
+        func_test_copy tmpfile0 tmpfile8
+
+        # Copy ACLs from a file that has no ACLs.
+        echo > tmpfile9
+        chmod a+x tmpfile9
+        getacl tmpfile9 | setacl -b -U - tmpfile0
+        rm -f tmpfile9
+
+        func_test_copy tmpfile0 tmpfile9
+
+        ;;
+
+      aix)
+
+        # Set an ACL for a user.
+        { aclget tmpfile0 | sed -e 's/disabled$/enabled/'; echo "        permit --x u:$auid"; } | aclput tmpfile0
+
+        func_test_copy tmpfile0 tmpfile2
+
+        # Set an ACL for a group.
+        { aclget tmpfile0 | sed -e 's/disabled$/enabled/'; echo "        permit r-- g:$agid"; } | aclput tmpfile0
+
+        func_test_copy tmpfile0 tmpfile3
+
+        # Set an ACL for other.
+        chmod o+r tmpfile0
+
+        func_test_copy tmpfile0 tmpfile4
+
+        # Remove the ACL for the user.
+        aclget tmpfile0 | grep -v ' u:[^ ]*$' | aclput tmpfile0
+
+        func_test_copy tmpfile0 tmpfile5
+
+        # Remove the ACL for the group.
+        aclget tmpfile0 | grep -v ' g:[^ ]*$' | aclput tmpfile0
+
+        func_test_copy tmpfile0 tmpfile7
+
+        # Delete all optional ACLs.
+        aclget tmpfile0 | sed -e 's/enabled$/disabled/' | sed -e '/disabled$/q' | aclput tmpfile0
+
+        func_test_copy tmpfile0 tmpfile8
+
+        # Copy ACLs from a file that has no ACLs.
+        echo > tmpfile9
+        chmod a+x tmpfile9
+        aclget tmpfile9 | aclput tmpfile0
+        rm -f tmpfile9
+
+        func_test_copy tmpfile0 tmpfile9
+
+        ;;
+
+      macosx)
+
+        # Set an ACL for a user.
+        /bin/chmod +a "user:daemon allow execute" tmpfile0
+
+        func_test_copy tmpfile0 tmpfile2
+
+        # Set an ACL for a group.
+        /bin/chmod +a "group daemon allow read" tmpfile0
+
+        func_test_copy tmpfile0 tmpfile3
+
+        # Set an ACL for other.
+        chmod o+r tmpfile0
+
+        func_test_copy tmpfile0 tmpfile4
+
+        # Remove the ACL for the user.
+        /bin/chmod -a "user:daemon allow execute" tmpfile0
+
+        func_test_copy tmpfile0 tmpfile5
+
+        # Remove the ACL for the group.
+        /bin/chmod -a "group daemon allow read" tmpfile0
+
+        func_test_copy tmpfile0 tmpfile7
+
+        # Delete all optional ACLs.
+        /bin/chmod -N tmpfile0
+
+        func_test_copy tmpfile0 tmpfile8
+
+        # Copy ACLs from a file that has no ACLs.
+        echo > tmpfile9
+        chmod a+x tmpfile9
+        { /bin/ls -le tmpfile9 | sed -n -e 's/^ [0-9][0-9]*: //p'; echo; } | /bin/chmod -E tmpfile0
+        rm -f tmpfile9
+
+        func_test_copy tmpfile0 tmpfile9
+
+        ;;
+
+      irix)
+
+        # Set an ACL for a user.
+        /sbin/chacl user:$auid:--x tmpfile0
+
+        func_test_copy tmpfile0 tmpfile2
+
+        # Set an ACL for a group.
+        /sbin/chacl user:$auid:--x,group:$agid:r-- tmpfile0
+
+        func_test_copy tmpfile0 tmpfile3
+
+        # Set an ACL for other.
+        /sbin/chacl user:$auid:--x,group:$agid:r--,other::r-- tmpfile0
+
+        func_test_copy tmpfile0 tmpfile4
+
+        # Remove the ACL for the user.
+        /sbin/chacl group:$agid:r--,other::r-- tmpfile0
+
+        func_test_copy tmpfile0 tmpfile5
+
+        # Remove the ACL for other.
+        /sbin/chacl group:$agid:r-- tmpfile0
+
+        func_test_copy tmpfile0 tmpfile6
+
+        # Remove the ACL for the group.
+        /sbin/chacl , tmpfile0
+
+        func_test_copy tmpfile0 tmpfile7
+
+        ;;
+
+    esac
+  fi
+
+  rm -f tmpfile[0-9] tmpaclout[12]
+) || exit 1
+
+rm -rf "$tmp"
+exit 0