Subject: bug#14295: closed (Re: Support copy-file ACLs for Solaris etc.)

From: [email-masked] (GNU bug Tracking System)
Date: Tue, 07 May 2013 21:39:02 +0000

Your bug report

#14295: Support copy-file ACLs for Solaris etc.

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
14295: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=14295
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: Support copy-file ACLs for Solaris etc.
From: Paul Eggert <[email-masked]>
To: Eli Zaretskii <[email-masked]>
Cc: [email-masked]
Date: Tue, 07 May 2013 14:36:54 -0700
List-Id: <debbugs-submit.debbugs.gnu.org>

On 04/29/13 10:07, Eli Zaretskii wrote:

> That almost works, but there are 2 issues:
> 
>  . I'd prefer to have the definition of EOPNOTSUPP in nt/inc/ms-w32.h,
>    to make synchronization of config.nt with src/config.in easier.
> 
>  . More importantly, ENOTSUP is defined on Windows with the same value
>    as ENOSYS (see ms-w32.h), so acl-errno-valid.c will fail to compile
>    due to 2 identical case values in a switch.

Thanks, I fixed those, installed it as trunk bzr 112507,
and am marking this bug as done.

Subject: Support copy-file ACLs for Solaris etc.
From: Paul Eggert <[email-masked]>
To: [email-masked]
Cc: Eli Zaretskii <[email-masked]>
Date: Sat, 27 Apr 2013 20:33:19 -0700
List-Id: <debbugs-submit.debbugs.gnu.org>

Tags: patch

Recently copy-file was augmented to add support for
copying ACLs on abandoned-POSIX-style hosts.  Here's
an additional patch to add support for copying ACLs on
Solaris, HP-UX, etc.  Basically, the idea is to use
Gnulib's support for ACLs.  I've tested this on
GNU/Linux and Solaris, but not on Microsoft platforms,
and am CC'ing this to Eli as a heads-up for that.

This changes the 'configure' option from --without-acl to
--disable-acl if one wishes to disable ACL support when
configuring Emacs; this is the option spelling that other GNU
packages use.
=== modified file 'ChangeLog'
--- ChangeLog	2013-04-27 19:30:33 +0000
+++ ChangeLog	2013-04-27 19:40:49 +0000
@@ -1,5 +1,16 @@
 2013-04-27  Paul Eggert  <[email-masked]>
 
+	Use Gnulib ACL implementation, for benefit of Solaris etc.
+	* configure.ac: Remove -with-acl option, since Gnulib does that for
+	us now.
+	(LIBACL_LIBS): Remove; no longer needed.
+	* lib/Makefile.am (CLEANFILES, SUFFIXES): New (empty) macros,
+	for the benefit of the new ACL implementation.
+	* lib/acl-errno-valid.c, lib/acl-internal.h, lib/acl.h:
+	* lib/acl_entries.c, lib/file-has-acl.c, lib/qcopy-acl.c:
+	* lib/qset-acl.c, m4/acl.m4: New files, taken from gnulib.
+	* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
+
 	Merge from gnulib, incorporating:
 	2013-04-27 alignof, intprops, malloca: port better to IBM's C compiler

=== modified file 'admin/ChangeLog'
--- admin/ChangeLog	2013-04-02 01:18:40 +0000
+++ admin/ChangeLog	2013-04-17 05:21:33 +0000
@@ -1,3 +1,8 @@
+2013-04-17  Paul Eggert  <[email-masked]>
+
+	Use Gnulib ACL implementation, for benefit of Solaris etc.
+	* merge-gnulib (GNULIB_MODULES): Add qacl.
+
 2013-04-01  Paul Eggert  <[email-masked]>
 
 	Use UTF-8 for most files with non-ASCII characters (Bug#13936).

=== modified file 'admin/merge-gnulib'
--- admin/merge-gnulib	2013-03-13 18:42:22 +0000
+++ admin/merge-gnulib	2013-04-17 05:21:33 +0000
@@ -33,7 +33,7 @@
   getloadavg getopt-gnu gettime gettimeofday
   ignore-value intprops largefile lstat
   manywarnings memrchr mktime
-  pselect pthread_sigmask putenv readlink readlinkat
+  pselect pthread_sigmask putenv qacl readlink readlinkat
   sig2str socklen stat-time stdalign stdarg stdbool stdio
   strftime strtoimax strtoumax symlink sys_stat
   sys_time time timer-time timespec-add timespec-sub unsetenv utimens

=== modified file 'configure.ac'
--- configure.ac	2013-04-26 19:31:09 +0000
+++ configure.ac	2013-04-27 19:40:49 +0000
@@ -199,7 +199,6 @@
 OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
 OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support])
 OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
-OPTION_DEFAULT_ON([acl],[don't compile with ACL support])
 OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
 OPTION_DEFAULT_ON([inotify],[don't compile with inotify (file-watch) support])
 
@@ -2185,23 +2184,6 @@
   AC_DEFINE(HAVE_INOTIFY, 1, [Define to 1 to use inotify.])
 fi
 
-dnl POSIX ACL support: provided by libacl on GNU/Linux, by libc on FreeBSD.
-HAVE_POSIX_ACL=no
-LIBACL_LIBS=
-if test "${with_acl}" = "yes"; then
-  AC_CHECK_LIB([acl], [acl_set_file], HAVE_POSIX_ACL=yes, HAVE_POSIX_ACL=no)
-  if test "$HAVE_POSIX_ACL" = yes; then
-    AC_DEFINE(HAVE_POSIX_ACL, 1, [Define to 1 if using POSIX ACL support.])
-    LIBACL_LIBS=-lacl
-  else
-    AC_CHECK_FUNC(acl_set_file, HAVE_POSIX_ACL=yes, HAVE_POSIX_ACL=no)
-    if test "$HAVE_POSIX_ACL" = yes; then
-      AC_DEFINE(HAVE_POSIX_ACL, 1, [Define to 1 if using POSIX ACL support.])
-    fi
- fi
-fi
-AC_SUBST(LIBACL_LIBS)
-
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
 HAVE_XAW3D=no

=== modified file 'etc/ChangeLog'
--- etc/ChangeLog	2013-04-24 16:50:14 +0000
+++ etc/ChangeLog	2013-04-27 19:40:49 +0000
@@ -1,3 +1,9 @@
+2013-04-27  Paul Eggert  <[email-masked]>
+
+	Use Gnulib ACL implementation, for benefit of Solaris etc.
+	* NEWS: Emacs is no longer limited to POSIX ACLs.  --disable-acl,
+	not --without-acl, since we're now using Gnulib's implementation.
+
 2013-04-24  Tassilo Horn  <[email-masked]>
 
 	* themes/tsdh-dark-theme.el (tsdh-dark): Add ido faces and remove

=== modified file 'etc/NEWS'
--- etc/NEWS	2013-04-27 20:55:00 +0000
+++ etc/NEWS	2013-04-28 00:00:19 +0000
@@ -23,10 +23,10 @@
 
 * Installation Changes in Emacs 24.4
 
-** Emacs can be compiled with POSIX ACL support.
+** Emacs can be compiled with ACL support.
 This happens by default if a suitable support library is found at
 build time, like libacl on GNU/Linux.  To prevent this, use the
-configure option `--without-acl'.
+configure option `--disable-acl'.
 
 ** The configure option --with-crt-dir has been removed.
 It is no longer needed, as the crt*.o files are no longer linked specially.

=== modified file 'lib/Makefile.am'
--- lib/Makefile.am	2013-04-07 06:21:40 +0000
+++ lib/Makefile.am	2013-04-17 05:21:33 +0000
@@ -1,8 +1,10 @@
 BUILT_SOURCES =
+CLEANFILES =
 EXTRA_DIST =
 MOSTLYCLEANDIRS =
 MOSTLYCLEANFILES =
 noinst_LIBRARIES =
+SUFFIXES =
 
 AM_CFLAGS = $(PROFILING_CFLAGS) $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS)
 DEFAULT_INCLUDES = -I. -I$(top_srcdir)/lib -I../src -I$(top_srcdir)/src

=== added file 'lib/acl-errno-valid.c'
--- lib/acl-errno-valid.c	1970-01-01 00:00:00 +0000
+++ lib/acl-errno-valid.c	2013-04-17 05:21:33 +0000
@@ -0,0 +1,48 @@
+/* Test whether ACLs are well supported on this system.
+
+   Copyright 2013 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 Paul Eggert.  */
+
+#include <config.h>
+
+#include <acl.h>
+
+#include <errno.h>
+
+/* Return true if errno value ERRNUM indicates that ACLs are well
+   supported on this system.  ERRNUM should be an errno value obtained
+   after an ACL-related system call fails.  */
+bool
+acl_errno_valid (int errnum)
+{
+  /* Recognize some common errors such as from an NFS mount that does
+     not support ACLs, even when local drives do.  */
+  switch (errnum)
+    {
+    case EBUSY: return false;
+    case EINVAL: return false;
+#if defined __APPLE__ && defined __MACH__
+    case ENOENT: return false;
+#endif
+    case ENOSYS: return false;
+#if defined ENOTSUP && ENOTSUP != EOPNOTSUPP
+    case ENOTSUP: return false;
+#endif
+    case EOPNOTSUPP: return false;
+    default: return true;
+    }
+}

=== added file 'lib/acl-internal.h'
--- lib/acl-internal.h	1970-01-01 00:00:00 +0000
+++ lib/acl-internal.h	2013-04-17 05:21:33 +0000
@@ -0,0 +1,250 @@
+/* Internal implementation of access control lists.
+
+   Copyright (C) 2002-2003, 2005-2013 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 Paul Eggert, Andreas Grünbacher, and Bruno Haible.  */
+
+#include "acl.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+/* All systems define the ACL related API in <sys/acl.h>.  */
+#if HAVE_SYS_ACL_H
+# include <sys/acl.h>
+#endif
+#if defined HAVE_FACL && ! defined GETACLCNT && defined ACL_CNT
+# define GETACLCNT ACL_CNT
+#endif
+
+/* On Linux, additional ACL related API is available in <acl/libacl.h>.  */
+#ifdef HAVE_ACL_LIBACL_H
+# include <acl/libacl.h>
+#endif
+
+/* On HP-UX >= 11.11, additional ACL API is available in <aclv.h>.  */
+#if HAVE_ACLV_H
+# include <sys/types.h>
+# include <aclv.h>
+/* HP-UX 11.11 lacks these declarations.  */
+extern int acl (char *, int, int, struct acl *);
+extern int aclsort (int, int, struct acl *);
+#endif
+
+#include <errno.h>
+
+#include <limits.h>
+#ifndef MIN
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
+#ifndef HAVE_FCHMOD
+# define HAVE_FCHMOD false
+# define fchmod(fd, mode) (-1)
+#endif
+
+_GL_INLINE_HEADER_BEGIN
+#ifndef ACL_INTERNAL_INLINE
+# define ACL_INTERNAL_INLINE _GL_INLINE
+#endif
+
+#if USE_ACL
+
+# if HAVE_ACL_GET_FILE
+/* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
+/* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
+
+#  ifndef MIN_ACL_ENTRIES
+#   define MIN_ACL_ENTRIES 4
+#  endif
+
+/* POSIX 1003.1e (draft 17) */
+#  ifdef HAVE_ACL_GET_FD
+/* Most platforms have a 1-argument acl_get_fd, only OSF/1 has a 2-argument
+   macro(!).  */
+#   if HAVE_ACL_FREE_TEXT /* OSF/1 */
+ACL_INTERNAL_INLINE acl_t
+rpl_acl_get_fd (int fd)
+{
+  return acl_get_fd (fd, ACL_TYPE_ACCESS);
+}
+#    undef acl_get_fd
+#    define acl_get_fd rpl_acl_get_fd
+#   endif
+#  else
+#   define HAVE_ACL_GET_FD false
+#   undef acl_get_fd
+#   define acl_get_fd(fd) (NULL)
+#  endif
+
+/* POSIX 1003.1e (draft 17) */
+#  ifdef HAVE_ACL_SET_FD
+/* Most platforms have a 2-argument acl_set_fd, only OSF/1 has a 3-argument
+   macro(!).  */
+#   if HAVE_ACL_FREE_TEXT /* OSF/1 */
+ACL_INTERNAL_INLINE int
+rpl_acl_set_fd (int fd, acl_t acl)
+{
+  return acl_set_fd (fd, ACL_TYPE_ACCESS, acl);
+}
+#    undef acl_set_fd
+#    define acl_set_fd rpl_acl_set_fd
+#   endif
+#  else
+#   define HAVE_ACL_SET_FD false
+#   undef acl_set_fd
+#   define acl_set_fd(fd, acl) (-1)
+#  endif
+
+/* POSIX 1003.1e (draft 13) */
+#  if ! HAVE_ACL_FREE_TEXT
+#   define acl_free_text(buf) acl_free (buf)
+#  endif
+
+/* Linux-specific */
+#  ifndef HAVE_ACL_EXTENDED_FILE
+#   define HAVE_ACL_EXTENDED_FILE false
+#   define acl_extended_file(name) (-1)
+#  endif
+
+/* Linux-specific */
+#  ifndef HAVE_ACL_FROM_MODE
+#   define HAVE_ACL_FROM_MODE false
+#   define acl_from_mode(mode) (NULL)
+#  endif
+
+/* Set to 1 if a file's mode is implicit by the ACL.
+   Set to 0 if a file's mode is stored independently from the ACL.  */
+#  if (HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP) || defined __sgi /* Mac OS X, IRIX */
+#   define MODE_INSIDE_ACL 0
+#  else
+#   define MODE_INSIDE_ACL 1
+#  endif
+
+/* Return the number of entries in ACL.
+   Return -1 and set errno upon failure to determine it.  */
+/* Define a replacement for acl_entries if needed. (Only Linux has it.)  */
+#  if !HAVE_ACL_ENTRIES
+#   define acl_entries rpl_acl_entries
+extern int acl_entries (acl_t);
+#  endif
+
+#  if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
+/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
+   Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial.  */
+extern int acl_extended_nontrivial (acl_t);
+#  else
+/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
+   Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
+   Return -1 and set errno upon failure to determine it.  */
+extern int acl_access_nontrivial (acl_t);
+#  endif
+
+# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
+
+/* Set to 1 if a file's mode is implicit by the ACL.
+   Set to 0 if a file's mode is stored independently from the ACL.  */
+#  if defined __CYGWIN__ /* Cygwin */
+#   define MODE_INSIDE_ACL 0
+#  else /* Solaris */
+#   define MODE_INSIDE_ACL 1
+#  endif
+
+/* Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+extern int acl_nontrivial (int count, aclent_t *entries);
+
+#  ifdef ACE_GETACL /* Solaris 10 */
+
+/* Test an ACL retrieved with ACE_GETACL.
+   Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+extern int acl_ace_nontrivial (int count, ace_t *entries);
+
+/* Definitions for when the built executable is executed on Solaris 10
+   (newer version) or Solaris 11.  */
+/* For a_type.  */
+#   define OLD_ALLOW 0
+#   define OLD_DENY  1
+#   define NEW_ACE_ACCESS_ALLOWED_ACE_TYPE 0 /* replaces ALLOW */
+#   define NEW_ACE_ACCESS_DENIED_ACE_TYPE  1 /* replaces DENY */
+/* For a_flags.  */
+#   define OLD_ACE_OWNER            0x0100
+#   define OLD_ACE_GROUP            0x0200
+#   define OLD_ACE_OTHER            0x0400
+#   define NEW_ACE_OWNER            0x1000
+#   define NEW_ACE_GROUP            0x2000
+#   define NEW_ACE_IDENTIFIER_GROUP 0x0040
+#   define NEW_ACE_EVERYONE         0x4000
+/* For a_access_mask.  */
+#   define NEW_ACE_READ_DATA         0x001 /* corresponds to 'r' */
+#   define NEW_ACE_WRITE_DATA        0x002 /* corresponds to 'w' */
+#   define NEW_ACE_APPEND_DATA       0x004
+#   define NEW_ACE_READ_NAMED_ATTRS  0x008
+#   define NEW_ACE_WRITE_NAMED_ATTRS 0x010
+#   define NEW_ACE_EXECUTE           0x020
+#   define NEW_ACE_DELETE_CHILD      0x040
+#   define NEW_ACE_READ_ATTRIBUTES   0x080
+#   define NEW_ACE_WRITE_ATTRIBUTES  0x100
+#   define NEW_ACE_DELETE          0x10000
+#   define NEW_ACE_READ_ACL        0x20000
+#   define NEW_ACE_WRITE_ACL       0x40000
+#   define NEW_ACE_WRITE_OWNER     0x80000
+#   define NEW_ACE_SYNCHRONIZE    0x100000
+
+#  endif
+
+# elif HAVE_GETACL /* HP-UX */
+
+/* Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+extern int acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb);
+
+#  if HAVE_ACLV_H /* HP-UX >= 11.11 */
+
+/* Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+extern int aclv_nontrivial (int count, struct acl *entries);
+
+#  endif
+
+# elif HAVE_ACLX_GET && 0 /* AIX */
+
+/* TODO */
+
+# elif HAVE_STATACL /* older AIX */
+
+/* Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+extern int acl_nontrivial (struct acl *a);
+
+# elif HAVE_ACLSORT /* NonStop Kernel */
+
+/* Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+extern int acl_nontrivial (int count, struct acl *entries);
+
+# endif
+
+#endif
+
+_GL_INLINE_HEADER_END

=== added file 'lib/acl.h'
--- lib/acl.h	1970-01-01 00:00:00 +0000
+++ lib/acl.h	2013-04-17 05:21:33 +0000
@@ -0,0 +1,30 @@
+/* acl.c - access control lists
+
+   Copyright (C) 2002, 2008-2013 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 Paul Eggert.  */
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+bool acl_errno_valid (int) _GL_ATTRIBUTE_CONST;
+int file_has_acl (char const *, struct stat const *);
+int qset_acl (char const *, int, mode_t);
+int set_acl (char const *, int, mode_t);
+int qcopy_acl (char const *, int, char const *, int, mode_t);
+int copy_acl (char const *, int, char const *, int, mode_t);
+int chmod_or_fchmod (char const *, int, mode_t);

=== added file 'lib/acl_entries.c'
--- lib/acl_entries.c	1970-01-01 00:00:00 +0000
+++ lib/acl_entries.c	2013-04-17 05:21:33 +0000
@@ -0,0 +1,75 @@
+/* Return the number of entries in an ACL.
+
+   Copyright (C) 2002-2003, 2005-2013 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 Paul Eggert and Andreas Gruenbacher.  */
+
+#include <config.h>
+
+#include "acl-internal.h"
+
+/* This file assumes POSIX-draft like ACLs
+   (Linux, FreeBSD, Mac OS X, IRIX, Tru64).  */
+
+/* Return the number of entries in ACL.
+   Return -1 and set errno upon failure to determine it.  */
+
+int
+acl_entries (acl_t acl)
+{
+  int count = 0;
+
+  if (acl != NULL)
+    {
+#if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD, Mac OS X */
+# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
+      /* acl_get_entry returns 0 when it successfully fetches an entry,
+         and -1/EINVAL at the end.  */
+      acl_entry_t ace;
+      int got_one;
+
+      for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
+           got_one >= 0;
+           got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
+        count++;
+# else /* Linux, FreeBSD */
+      /* acl_get_entry returns 1 when it successfully fetches an entry,
+         and 0 at the end.  */
+      acl_entry_t ace;
+      int got_one;
+
+      for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
+           got_one > 0;
+           got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
+        count++;
+      if (got_one < 0)
+        return -1;
+# endif
+#else /* IRIX, Tru64 */
+# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
+      /* Don't use acl_get_entry: it is undocumented.  */
+      count = acl->acl_cnt;
+# endif
+# if HAVE_ACL_FREE_TEXT /* Tru64 */
+      /* Don't use acl_get_entry: it takes only one argument and does not
+         work.  */
+      count = acl->acl_num;
+# endif
+#endif
+    }
+
+  return count;
+}

=== added file 'lib/file-has-acl.c'
--- lib/file-has-acl.c	1970-01-01 00:00:00 +0000
+++ lib/file-has-acl.c	2013-04-18 01:35:08 +0000
@@ -0,0 +1,918 @@
+/* Test whether a file has a nontrivial access control list.
+
+   Copyright (C) 2002-2003, 2005-2013 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 Paul Eggert, Andreas Grünbacher, and Bruno Haible.  */
+
+/* Without this pragma, gcc 4.7.0 20120126 may suggest that the
+   file_has_acl function might be candidate for attribute 'const'  */
+#if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
+# pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
+#endif
+
+#include <config.h>
+
+#include "acl.h"
+
+#include "acl-internal.h"
+
+
+#if USE_ACL && HAVE_ACL_GET_FILE
+
+# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
+
+/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
+   Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial.  */
+int
+acl_extended_nontrivial (acl_t acl)
+{
+  /* acl is non-trivial if it is non-empty.  */
+  return (acl_entries (acl) > 0);
+}
+
+# else /* Linux, FreeBSD, IRIX, Tru64 */
+
+/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
+   Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
+   Return -1 and set errno upon failure to determine it.  */
+int
+acl_access_nontrivial (acl_t acl)
+{
+  /* acl is non-trivial if it has some entries other than for "user::",
+     "group::", and "other::".  Normally these three should be present
+     at least, allowing us to write
+        return (3 < acl_entries (acl));
+     but the following code is more robust.  */
+#  if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD */
+
+  acl_entry_t ace;
+  int got_one;
+
+  for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
+       got_one > 0;
+       got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
+    {
+      acl_tag_t tag;
+      if (acl_get_tag_type (ace, &tag) < 0)
+        return -1;
+      if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
+        return 1;
+    }
+  return got_one;
+
+#  else /* IRIX, Tru64 */
+#   if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
+  /* Don't use acl_get_entry: it is undocumented.  */
+
+  int count = acl->acl_cnt;
+  int i;
+
+  for (i = 0; i < count; i++)
+    {
+      acl_entry_t ace = &acl->acl_entry[i];
+      acl_tag_t tag = ace->ae_tag;
+
+      if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ
+            || tag == ACL_OTHER_OBJ))
+        return 1;
+    }
+  return 0;
+
+#   endif
+#   if HAVE_ACL_FREE_TEXT /* Tru64 */
+  /* Don't use acl_get_entry: it takes only one argument and does not work.  */
+
+  int count = acl->acl_num;
+  acl_entry_t ace;
+
+  for (ace = acl->acl_first; count > 0; ace = ace->next, count--)
+    {
+      acl_tag_t tag;
+      acl_perm_t perm;
+
+      tag = ace->entry->acl_type;
+      if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
+        return 1;
+
+      perm = ace->entry->acl_perm;
+      /* On Tru64, perm can also contain non-standard bits such as
+         PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ... */
+      if ((perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)) != 0)
+        return 1;
+    }
+  return 0;
+
+#   endif
+#  endif
+}
+
+# endif
+
+
+#elif USE_ACL && HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
+
+/* Test an ACL retrieved with GETACL.
+   Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+int
+acl_nontrivial (int count, aclent_t *entries)
+{
+  int i;
+
+  for (i = 0; i < count; i++)
+    {
+      aclent_t *ace = &entries[i];
+
+      /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
+         If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
+         We don't need to check ace->a_id in these cases.  */
+      if (!(ace->a_type == USER_OBJ
+            || ace->a_type == GROUP_OBJ
+            || ace->a_type == OTHER_OBJ
+            /* Note: Cygwin does not return a CLASS_OBJ ("mask:") entry
+               sometimes.  */
+            || ace->a_type == CLASS_OBJ))
+        return 1;
+    }
+  return 0;
+}
+
+# ifdef ACE_GETACL
+
+/* A shortcut for a bitmask.  */
+#  define NEW_ACE_WRITEA_DATA (NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA)
+
+/* Test an ACL retrieved with ACE_GETACL.
+   Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+int
+acl_ace_nontrivial (int count, ace_t *entries)
+{
+  int i;
+
+  /* The flags in the ace_t structure changed in a binary incompatible way
+     when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
+     How to distinguish the two conventions at runtime?
+     In the old convention, usually three ACEs have a_flags = ACE_OWNER /
+     ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400.  In the new
+     convention, these values are not used.  */
+  int old_convention = 0;
+
+  for (i = 0; i < count; i++)
+    if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER))
+      {
+        old_convention = 1;
+        break;
+      }
+
+  if (old_convention)
+    /* Running on Solaris 10.  */
+    for (i = 0; i < count; i++)
+      {
+        ace_t *ace = &entries[i];
+
+        /* Note:
+           If ace->a_flags = ACE_OWNER, ace->a_who is the st_uid from stat().
+           If ace->a_flags = ACE_GROUP, ace->a_who is the st_gid from stat().
+           We don't need to check ace->a_who in these cases.  */
+        if (!(ace->a_type == OLD_ALLOW
+              && (ace->a_flags == OLD_ACE_OWNER
+                  || ace->a_flags == OLD_ACE_GROUP
+                  || ace->a_flags == OLD_ACE_OTHER)))
+          return 1;
+      }
+  else
+    {
+      /* Running on Solaris 10 (newer version) or Solaris 11.  */
+      unsigned int access_masks[6] =
+        {
+          0, /* owner@ deny */
+          0, /* owner@ allow */
+          0, /* group@ deny */
+          0, /* group@ allow */
+          0, /* everyone@ deny */
+          0  /* everyone@ allow */
+        };
+
+      for (i = 0; i < count; i++)
+        {
+          ace_t *ace = &entries[i];
+          unsigned int index1;
+          unsigned int index2;
+
+          if (ace->a_type == NEW_ACE_ACCESS_ALLOWED_ACE_TYPE)
+            index1 = 1;
+          else if (ace->a_type == NEW_ACE_ACCESS_DENIED_ACE_TYPE)
+            index1 = 0;
+          else
+            return 1;
+
+          if (ace->a_flags == NEW_ACE_OWNER)
+            index2 = 0;
+          else if (ace->a_flags == (NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP))
+            index2 = 2;
+          else if (ace->a_flags == NEW_ACE_EVERYONE)
+            index2 = 4;
+          else
+            return 1;
+
+          access_masks[index1 + index2] |= ace->a_access_mask;
+        }
+
+      /* The same bit shouldn't be both allowed and denied.  */
+      if (access_masks[0] & access_masks[1])
+        return 1;
+      if (access_masks[2] & access_masks[3])
+        return 1;
+      if (access_masks[4] & access_masks[5])
+        return 1;
+
+      /* Check minimum masks.  */
+      if ((NEW_ACE_WRITE_NAMED_ATTRS
+           | NEW_ACE_WRITE_ATTRIBUTES
+           | NEW_ACE_WRITE_ACL
+           | NEW_ACE_WRITE_OWNER)
+          & ~ access_masks[1])
+        return 1;
+      access_masks[1] &= ~(NEW_ACE_WRITE_NAMED_ATTRS
+                           | NEW_ACE_WRITE_ATTRIBUTES
+                           | NEW_ACE_WRITE_ACL
+                           | NEW_ACE_WRITE_OWNER);
+      if ((NEW_ACE_READ_NAMED_ATTRS
+           | NEW_ACE_READ_ATTRIBUTES
+           | NEW_ACE_READ_ACL
+           | NEW_ACE_SYNCHRONIZE)
+          & ~ access_masks[5])
+        return 1;
+      access_masks[5] &= ~(NEW_ACE_READ_NAMED_ATTRS
+                           | NEW_ACE_READ_ATTRIBUTES
+                           | NEW_ACE_READ_ACL
+                           | NEW_ACE_SYNCHRONIZE);
+
+      /* Check the allowed or denied bits.  */
+      switch ((access_masks[0] | access_masks[1])
+              & ~(NEW_ACE_READ_NAMED_ATTRS
+                  | NEW_ACE_READ_ATTRIBUTES
+                  | NEW_ACE_READ_ACL
+                  | NEW_ACE_SYNCHRONIZE))
+        {
+        case 0:
+        case NEW_ACE_READ_DATA:
+        case                     NEW_ACE_WRITEA_DATA:
+        case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
+        case                                           NEW_ACE_EXECUTE:
+        case NEW_ACE_READ_DATA |                       NEW_ACE_EXECUTE:
+        case                     NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
+        case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
+          break;
+        default:
+          return 1;
+        }
+      switch ((access_masks[2] | access_masks[3])
+              & ~(NEW_ACE_READ_NAMED_ATTRS
+                  | NEW_ACE_READ_ATTRIBUTES
+                  | NEW_ACE_READ_ACL
+                  | NEW_ACE_SYNCHRONIZE))
+        {
+        case 0:
+        case NEW_ACE_READ_DATA:
+        case                     NEW_ACE_WRITEA_DATA:
+        case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
+        case                                           NEW_ACE_EXECUTE:
+        case NEW_ACE_READ_DATA |                       NEW_ACE_EXECUTE:
+        case                     NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
+        case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
+          break;
+        default:
+          return 1;
+        }
+      switch ((access_masks[4] | access_masks[5])
+              & ~(NEW_ACE_WRITE_NAMED_ATTRS
+                  | NEW_ACE_WRITE_ATTRIBUTES
+                  | NEW_ACE_WRITE_ACL
+                  | NEW_ACE_WRITE_OWNER))
+        {
+        case 0:
+        case NEW_ACE_READ_DATA:
+        case                     NEW_ACE_WRITEA_DATA:
+        case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
+        case                                           NEW_ACE_EXECUTE:
+        case NEW_ACE_READ_DATA |                       NEW_ACE_EXECUTE:
+        case                     NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
+        case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
+          break;
+        default:
+          return 1;
+        }
+
+      /* Check that the NEW_ACE_WRITE_DATA and NEW_ACE_APPEND_DATA bits are
+         either both allowed or both denied.  */
+      if (((access_masks[0] & NEW_ACE_WRITE_DATA) != 0)
+          != ((access_masks[0] & NEW_ACE_APPEND_DATA) != 0))
+        return 1;
+      if (((access_masks[2] & NEW_ACE_WRITE_DATA) != 0)
+          != ((access_masks[2] & NEW_ACE_APPEND_DATA) != 0))
+        return 1;
+      if (((access_masks[4] & NEW_ACE_WRITE_DATA) != 0)
+          != ((access_masks[4] & NEW_ACE_APPEND_DATA) != 0))
+        return 1;
+    }
+
+  return 0;
+}
+
+# endif
+
+#elif USE_ACL && HAVE_GETACL /* HP-UX */
+
+/* Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+int
+acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb)
+{
+  int i;
+
+  for (i = 0; i < count; i++)
+    {
+      struct acl_entry *ace = &entries[i];
+
+      if (!((ace->uid == sb->st_uid && ace->gid == ACL_NSGROUP)
+            || (ace->uid == ACL_NSUSER && ace->gid == sb->st_gid)
+            || (ace->uid == ACL_NSUSER && ace->gid == ACL_NSGROUP)))
+        return 1;
+    }
+  return 0;
+}
+
+# if HAVE_ACLV_H /* HP-UX >= 11.11 */
+
+/* Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+int
+aclv_nontrivial (int count, struct acl *entries)
+{
+  int i;
+
+  for (i = 0; i < count; i++)
+    {
+      struct acl *ace = &entries[i];
+
+      /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
+         If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
+         We don't need to check ace->a_id in these cases.  */
+      if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */
+            || ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */
+            || ace->a_type == CLASS_OBJ
+            || ace->a_type == OTHER_OBJ))
+        return 1;
+    }
+  return 0;
+}
+
+# endif
+
+#elif USE_ACL && (HAVE_ACLX_GET || HAVE_STATACL) /* AIX */
+
+/* Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+int
+acl_nontrivial (struct acl *a)
+{
+  /* The normal way to iterate through an ACL is like this:
+       struct acl_entry *ace;
+       for (ace = a->acl_ext; ace != acl_last (a); ace = acl_nxt (ace))
+         {
+           struct ace_id *aei;
+           switch (ace->ace_type)
+             {
+             case ACC_PERMIT:
+             case ACC_DENY:
+             case ACC_SPECIFY:
+               ...;
+             }
+           for (aei = ace->ace_id; aei != id_last (ace); aei = id_nxt (aei))
+             ...
+         }
+   */
+  return (acl_last (a) != a->acl_ext ? 1 : 0);
+}
+
+# if HAVE_ACLX_GET && defined ACL_AIX_WIP /* newer AIX */
+
+/* Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+int
+acl_nfs4_nontrivial (nfs4_acl_int_t *a)
+{
+#  if 1 /* let's try this first */
+  return (a->aclEntryN > 0 ? 1 : 0);
+#  else
+  int count = a->aclEntryN;
+  int i;
+
+  for (i = 0; i < count; i++)
+    {
+      nfs4_ace_int_t *ace = &a->aclEntry[i];
+
+      if (!((ace->flags & ACE4_ID_SPECIAL) != 0
+            && (ace->aceWho.special_whoid == ACE4_WHO_OWNER
+                || ace->aceWho.special_whoid == ACE4_WHO_GROUP
+                || ace->aceWho.special_whoid == ACE4_WHO_EVERYONE)
+            && ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE
+            && ace->aceFlags == 0
+            && (ace->aceMask & ~(ACE4_READ_DATA | ACE4_LIST_DIRECTORY
+                                 | ACE4_WRITE_DATA | ACE4_ADD_FILE
+                                 | ACE4_EXECUTE)) == 0))
+        return 1;
+    }
+  return 0;
+#  endif
+}
+
+# endif
+
+#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
+
+/* Test an ACL retrieved with ACL_GET.
+   Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+int
+acl_nontrivial (int count, struct acl *entries)
+{
+  int i;
+
+  for (i = 0; i < count; i++)
+    {
+      struct acl *ace = &entries[i];
+
+      /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
+         If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
+         We don't need to check ace->a_id in these cases.  */
+      if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */
+            || ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */
+            || ace->a_type == CLASS_OBJ
+            || ace->a_type == OTHER_OBJ))
+        return 1;
+    }
+  return 0;
+}
+
+#endif
+
+
+/* Return 1 if NAME has a nontrivial access control list, 0 if NAME
+   only has no or a base access control list, and -1 (setting errno)
+   on error.  SB must be set to the stat buffer of NAME, obtained
+   through stat() or lstat().  */
+
+int
+file_has_acl (char const *name, struct stat const *sb)
+{
+#if USE_ACL
+  if (! S_ISLNK (sb->st_mode))
+    {
+# if HAVE_ACL_GET_FILE
+
+      /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
+      /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
+      int ret;
+
+      if (HAVE_ACL_EXTENDED_FILE) /* Linux */
+        {
+          /* On Linux, acl_extended_file is an optimized function: It only
+             makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
+             ACL_TYPE_DEFAULT.  */
+          ret = acl_extended_file (name);
+        }
+      else /* FreeBSD, Mac OS X, IRIX, Tru64 */
+        {
+#  if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
+          /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
+             and acl_get_file (name, ACL_TYPE_DEFAULT)
+             always return NULL / EINVAL.  There is no point in making
+             these two useless calls.  The real ACL is retrieved through
+             acl_get_file (name, ACL_TYPE_EXTENDED).  */
+          acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
+          if (acl)
+            {
+              ret = acl_extended_nontrivial (acl);
+              acl_free (acl);
+            }
+          else
+            ret = -1;
+#  else /* FreeBSD, IRIX, Tru64 */
+          acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
+          if (acl)
+            {
+              int saved_errno;
+
+              ret = acl_access_nontrivial (acl);
+              saved_errno = errno;
+              acl_free (acl);
+              errno = saved_errno;
+#   if HAVE_ACL_FREE_TEXT /* Tru64 */
+              /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
+                 returns NULL with errno not set.  There is no point in
+                 making this call.  */
+#   else /* FreeBSD, IRIX */
+              /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
+                 and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
+                 either both succeed or both fail; it depends on the
+                 file system.  Therefore there is no point in making the second
+                 call if the first one already failed.  */
+              if (ret == 0 && S_ISDIR (sb->st_mode))
+                {
+                  acl = acl_get_file (name, ACL_TYPE_DEFAULT);
+                  if (acl)
+                    {
+                      ret = (0 < acl_entries (acl));
+                      acl_free (acl);
+                    }
+                  else
+                    ret = -1;
+                }
+#   endif
+            }
+          else
+            ret = -1;
+#  endif
+        }
+      if (ret < 0)
+        return - acl_errno_valid (errno);
+      return ret;
+
+# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
+
+#  if defined ACL_NO_TRIVIAL
+
+      /* Solaris 10 (newer version), which has additional API declared in
+         <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
+         acl_fromtext, ...).  */
+      return acl_trivial (name);
+
+#  else /* Solaris, Cygwin, general case */
+
+      /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
+         of Unixware.  The acl() call returns the access and default ACL both
+         at once.  */
+      {
+        /* Initially, try to read the entries into a stack-allocated buffer.
+           Use malloc if it does not fit.  */
+        enum
+          {
+            alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */
+            alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t))
+          };
+        aclent_t buf[alloc_init];
+        size_t alloc = alloc_init;
+        aclent_t *entries = buf;
+        aclent_t *malloced = NULL;
+        int count;
+
+        for (;;)
+          {
+            count = acl (name, GETACL, alloc, entries);
+            if (count < 0 && errno == ENOSPC)
+              {
+                /* Increase the size of the buffer.  */
+                free (malloced);
+                if (alloc > alloc_max / 2)
+                  {
+                    errno = ENOMEM;
+                    return -1;
+                  }
+                alloc = 2 * alloc; /* <= alloc_max */
+                entries = malloced =
+                  (aclent_t *) malloc (alloc * sizeof (aclent_t));
+                if (entries == NULL)
+                  {
+                    errno = ENOMEM;
+                    return -1;
+                  }
+                continue;
+              }
+            break;
+          }
+        if (count < 0)
+          {
+            if (errno == ENOSYS || errno == ENOTSUP)
+              ;
+            else
+              {
+                int saved_errno = errno;
+                free (malloced);
+                errno = saved_errno;
+                return -1;
+              }
+          }
+        else if (count == 0)
+          ;
+        else
+          {
+            /* Don't use MIN_ACL_ENTRIES:  It's set to 4 on Cygwin, but Cygwin
+               returns only 3 entries for files with no ACL.  But this is safe:
+               If there are more than 4 entries, there cannot be only the
+               "user::", "group::", "other:", and "mask:" entries.  */
+            if (count > 4)
+              {
+                free (malloced);
+                return 1;
+              }
+
+            if (acl_nontrivial (count, entries))
+              {
+                free (malloced);
+                return 1;
+              }
+          }
+        free (malloced);
+      }
+
+#   ifdef ACE_GETACL
+      /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
+         file systems (whereas the other ones are used in UFS file systems).  */
+      {
+        /* Initially, try to read the entries into a stack-allocated buffer.
+           Use malloc if it does not fit.  */
+        enum
+          {
+            alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
+            alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
+          };
+        ace_t buf[alloc_init];
+        size_t alloc = alloc_init;
+        ace_t *entries = buf;
+        ace_t *malloced = NULL;
+        int count;
+
+        for (;;)
+          {
+            count = acl (name, ACE_GETACL, alloc, entries);
+            if (count < 0 && errno == ENOSPC)
+              {
+                /* Increase the size of the buffer.  */
+                free (malloced);
+                if (alloc > alloc_max / 2)
+                  {
+                    errno = ENOMEM;
+                    return -1;
+                  }
+                alloc = 2 * alloc; /* <= alloc_max */
+                entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
+                if (entries == NULL)
+                  {
+                    errno = ENOMEM;
+                    return -1;
+                  }
+                continue;
+              }
+            break;
+          }
+        if (count < 0)
+          {
+            if (errno == ENOSYS || errno == EINVAL)
+              ;
+            else
+              {
+                int saved_errno = errno;
+                free (malloced);
+                errno = saved_errno;
+                return -1;
+              }
+          }
+        else if (count == 0)
+          ;
+        else
+          {
+            /* In the old (original Solaris 10) convention:
+               If there are more than 3 entries, there cannot be only the
+               ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
+               In the newer Solaris 10 and Solaris 11 convention:
+               If there are more than 6 entries, there cannot be only the
+               ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
+               NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
+               NEW_ACE_ACCESS_DENIED_ACE_TYPE.  */
+            if (count > 6)
+              {
+                free (malloced);
+                return 1;
+              }
+
+            if (acl_ace_nontrivial (count, entries))
+              {
+                free (malloced);
+                return 1;
+              }
+          }
+        free (malloced);
+      }
+#   endif
+
+      return 0;
+#  endif
+
+# elif HAVE_GETACL /* HP-UX */
+
+      {
+        struct acl_entry entries[NACLENTRIES];
+        int count;
+
+        count = getacl (name, NACLENTRIES, entries);
+
+        if (count < 0)
+          {
+            /* ENOSYS is seen on newer HP-UX versions.
+               EOPNOTSUPP is typically seen on NFS mounts.
+               ENOTSUP was seen on Quantum StorNext file systems (cvfs).  */
+            if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
+              ;
+            else
+              return -1;
+          }
+        else if (count == 0)
+          return 0;
+        else /* count > 0 */
+          {
+            if (count > NACLENTRIES)
+              /* If NACLENTRIES cannot be trusted, use dynamic memory
+                 allocation.  */
+              abort ();
+
+            /* If there are more than 3 entries, there cannot be only the
+               (uid,%), (%,gid), (%,%) entries.  */
+            if (count > 3)
+              return 1;
+
+            {
+              struct stat statbuf;
+
+              if (stat (name, &statbuf) < 0)
+                return -1;
+
+              return acl_nontrivial (count, entries, &statbuf);
+            }
+          }
+      }
+
+#  if HAVE_ACLV_H /* HP-UX >= 11.11 */
+
+      {
+        struct acl entries[NACLVENTRIES];
+        int count;
+
+        count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
+
+        if (count < 0)
+          {
+            /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
+               EINVAL is seen on NFS in HP-UX 11.31.  */
+            if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
+              ;
+            else
+              return -1;
+          }
+        else if (count == 0)
+          return 0;
+        else /* count > 0 */
+          {
+            if (count > NACLVENTRIES)
+              /* If NACLVENTRIES cannot be trusted, use dynamic memory
+                 allocation.  */
+              abort ();
+
+            /* If there are more than 4 entries, there cannot be only the
+               four base ACL entries.  */
+            if (count > 4)
+              return 1;
+
+            return aclv_nontrivial (count, entries);
+          }
+      }
+
+#  endif
+
+# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
+
+      acl_type_t type;
+      char aclbuf[1024];
+      void *acl = aclbuf;
+      size_t aclsize = sizeof (aclbuf);
+      mode_t mode;
+
+      for (;;)
+        {
+          /* The docs say that type being 0 is equivalent to ACL_ANY, but it
+             is not true, in AIX 5.3.  */
+          type.u64 = ACL_ANY;
+          if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
+            break;
+          if (errno == ENOSYS)
+            return 0;
+          if (errno != ENOSPC)
+            {
+              if (acl != aclbuf)
+                {
+                  int saved_errno = errno;
+                  free (acl);
+                  errno = saved_errno;
+                }
+              return -1;
+            }
+          aclsize = 2 * aclsize;
+          if (acl != aclbuf)
+            free (acl);
+          acl = malloc (aclsize);
+          if (acl == NULL)
+            {
+              errno = ENOMEM;
+              return -1;
+            }
+        }
+
+      if (type.u64 == ACL_AIXC)
+        {
+          int result = acl_nontrivial ((struct acl *) acl);
+          if (acl != aclbuf)
+            free (acl);
+          return result;
+        }
+      else if (type.u64 == ACL_NFS4)
+        {
+          int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
+          if (acl != aclbuf)
+            free (acl);
+          return result;
+        }
+      else
+        {
+          /* A newer type of ACL has been introduced in the system.
+             We should better support it.  */
+          if (acl != aclbuf)
+            free (acl);
+          errno = EINVAL;
+          return -1;
+        }
+
+# elif HAVE_STATACL /* older AIX */
+
+      union { struct acl a; char room[4096]; } u;
+
+      if (statacl (name, STX_NORMAL, &u.a, sizeof (u)) < 0)
+        return -1;
+
+      return acl_nontrivial (&u.a);
+
+# elif HAVE_ACLSORT /* NonStop Kernel */
+
+      {
+        struct acl entries[NACLENTRIES];
+        int count;
+
+        count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
+
+        if (count < 0)
+          {
+            if (errno == ENOSYS || errno == ENOTSUP)
+              ;
+            else
+              return -1;
+          }
+        else if (count == 0)
+          return 0;
+        else /* count > 0 */
+          {
+            if (count > NACLENTRIES)
+              /* If NACLENTRIES cannot be trusted, use dynamic memory
+                 allocation.  */
+              abort ();
+
+            /* If there are more than 4 entries, there cannot be only the
+               four base ACL entries.  */
+            if (count > 4)
+              return 1;
+
+            return acl_nontrivial (count, entries);
+          }
+      }
+
+# endif
+    }
+#endif
+
+  return 0;
+}

=== modified file 'lib/gnulib.mk'
--- lib/gnulib.mk	2013-03-13 18:42:22 +0000
+++ lib/gnulib.mk	2013-04-27 20:24:10 +0000
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=dup --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings memrchr mktime pselect pthread_sigmask putenv readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens warnings
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=dup --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings memrchr mktime pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens warnings

 MOSTLYCLEANFILES += core *.stackdump
@@ -561,6 +561,16 @@
 
 ## end   gnulib module putenv
 
+## begin gnulib module qacl
+
+libgnu_a_SOURCES += acl-errno-valid.c file-has-acl.c qcopy-acl.c qset-acl.c
+
+EXTRA_DIST += acl-internal.h acl.h acl_entries.c
+
+EXTRA_libgnu_a_SOURCES += acl_entries.c
+
+## end   gnulib module qacl
+
 ## begin gnulib module readlink

=== added file 'lib/qcopy-acl.c'
--- lib/qcopy-acl.c	1970-01-01 00:00:00 +0000
+++ lib/qcopy-acl.c	2013-04-17 05:21:33 +0000
@@ -0,0 +1,583 @@
+/* copy-acl.c - copy access control list from one file to another file
+
+   Copyright (C) 2002-2003, 2005-2013 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 Paul Eggert, Andreas Grünbacher, and Bruno Haible.  */
+
+#include <config.h>
+
+#include "acl.h"
+
+#include "acl-internal.h"
+
+
+/* Copy access control lists from one file to another. If SOURCE_DESC is
+   a valid file descriptor, use file descriptor operations, else use
+   filename based operations on SRC_NAME. Likewise for DEST_DESC and
+   DST_NAME.
+   If access control lists are not available, fchmod the target file to
+   MODE.  Also sets the non-permission bits of the destination file
+   (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
+   Return 0 if successful.
+   Return -2 and set errno for an error relating to the source file.
+   Return -1 and set errno for an error relating to the destination file.  */
+
+int
+qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
+           int dest_desc, mode_t mode)
+{
+#if USE_ACL && HAVE_ACL_GET_FILE
+  /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
+  /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
+# if !HAVE_ACL_TYPE_EXTENDED
+  /* Linux, FreeBSD, IRIX, Tru64 */
+
+  acl_t acl;
+  int ret;
+
+  if (HAVE_ACL_GET_FD && source_desc != -1)
+    acl = acl_get_fd (source_desc);
+  else
+    acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
+  if (acl == NULL)
+    {
+      if (! acl_errno_valid (errno))
+        return qset_acl (dst_name, dest_desc, mode);
+      else
+        return -2;
+    }
+
+  if (HAVE_ACL_SET_FD && dest_desc != -1)
+    ret = acl_set_fd (dest_desc, acl);
+  else
+    ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
+  if (ret != 0)
+    {
+      int saved_errno = errno;
+
+      if (! acl_errno_valid (errno) && !acl_access_nontrivial (acl))
+        {
+          acl_free (acl);
+          return chmod_or_fchmod (dst_name, dest_desc, mode);
+        }
+      else
+        {
+          acl_free (acl);
+          chmod_or_fchmod (dst_name, dest_desc, mode);
+          errno = saved_errno;
+          return -1;
+        }
+    }
+  else
+    acl_free (acl);
+
+  if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
+    {
+      /* We did not call chmod so far, and either the mode and the ACL are
+         separate or special bits are to be set which don't fit into ACLs.  */
+
+      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
+        return -1;
+    }
+
+  if (S_ISDIR (mode))
+    {
+      acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
+      if (acl == NULL)
+        return -2;
+
+      if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
+        {
+          int saved_errno = errno;
+
+          acl_free (acl);
+          errno = saved_errno;
+          return -1;
+        }
+      else
+        acl_free (acl);
+    }
+  return 0;
+
+# else /* HAVE_ACL_TYPE_EXTENDED */
+  /* Mac OS X */
+
+  /* On Mac OS X,  acl_get_file (name, ACL_TYPE_ACCESS)
+     and           acl_get_file (name, ACL_TYPE_DEFAULT)
+     always return NULL / EINVAL.  You have to use
+                   acl_get_file (name, ACL_TYPE_EXTENDED)
+     or            acl_get_fd (open (name, ...))
+     to retrieve an ACL.
+     On the other hand,
+                   acl_set_file (name, ACL_TYPE_ACCESS, acl)
+     and           acl_set_file (name, ACL_TYPE_DEFAULT, acl)
+     have the same effect as
+                   acl_set_file (name, ACL_TYPE_EXTENDED, acl):
+     Each of these calls sets the file's ACL.  */
+
+  acl_t acl;
+  int ret;
+
+  if (HAVE_ACL_GET_FD && source_desc != -1)
+    acl = acl_get_fd (source_desc);
+  else
+    acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
+  if (acl == NULL)
+    {
+      if (!acl_errno_valid (errno))
+        return qset_acl (dst_name, dest_desc, mode);
+      else
+        return -2;
+    }
+
+  if (HAVE_ACL_SET_FD && dest_desc != -1)
+    ret = acl_set_fd (dest_desc, acl);
+  else
+    ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
+  if (ret != 0)
+    {
+      int saved_errno = errno;
+
+      if (!acl_errno_valid (saved_errno) && !acl_extended_nontrivial (acl))
+        {
+          acl_free (acl);
+          return chmod_or_fchmod (dst_name, dest_desc, mode);
+        }
+      else
+        {
+          acl_free (acl);
+          chmod_or_fchmod (dst_name, dest_desc, mode);
+          errno = saved_errno;
+          return -1;
+        }
+    }
+  else
+    acl_free (acl);
+
+  /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly.  */
+  return chmod_or_fchmod (dst_name, dest_desc, mode);
+
+# endif
+
+#elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
+
+  /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
+     of Unixware.  The acl() call returns the access and default ACL both
+     at once.  */
+# ifdef ACE_GETACL
+  int ace_count;
+  ace_t *ace_entries;
+# endif
+  int count;
+  aclent_t *entries;
+  int did_chmod;
+  int saved_errno;
+  int ret;
+
+# ifdef ACE_GETACL
+  /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
+     file systems (whereas the other ones are used in UFS file systems).
+     There is an API
+       pathconf (name, _PC_ACL_ENABLED)
+       fpathconf (desc, _PC_ACL_ENABLED)
+     that allows to determine which of the two kinds of ACLs is supported
+     for the given file.  But some file systems may implement this call
+     incorrectly, so better not use it.
+     When fetching the source ACL, we simply fetch both ACL types.
+     When setting the destination ACL, we try either ACL types, assuming
+     that the kernel will translate the ACL from one form to the other.
+     (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
+     the description of ENOTSUP.)  */
+  for (;;)
+    {
+      ace_count = (source_desc != -1
+                   ? facl (source_desc, ACE_GETACLCNT, 0, NULL)
+                   : acl (src_name, ACE_GETACLCNT, 0, NULL));
+
+      if (ace_count < 0)
+        {
+          if (errno == ENOSYS || errno == EINVAL)
+            {
+              ace_count = 0;
+              ace_entries = NULL;
+              break;
+            }
+          else
+            return -2;
+        }
+
+      if (ace_count == 0)
+        {
+          ace_entries = NULL;
+          break;
+        }
+
+      ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t));
+      if (ace_entries == NULL)
+        {
+          errno = ENOMEM;
+          return -2;
+        }
+
+      ret = (source_desc != -1
+             ? facl (source_desc, ACE_GETACL, ace_count, ace_entries)
+             : acl (src_name, ACE_GETACL, ace_count, ace_entries));
+      if (ret < 0)
+        {
+          free (ace_entries);
+          if (errno == ENOSYS || errno == EINVAL)
+            {
+              ace_count = 0;
+              ace_entries = NULL;
+              break;
+            }
+          else
+            return -2;
+        }
+      if (ret == ace_count)
+        break;
+      /* Huh? The number of ACL entries changed since the last call.
+         Repeat.  */
+    }
+# endif
+
+  for (;;)
+    {
+      count = (source_desc != -1
+               ? facl (source_desc, GETACLCNT, 0, NULL)
+               : acl (src_name, GETACLCNT, 0, NULL));
+
+      if (count < 0)
+        {
+          if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
+            {
+              count = 0;
+              entries = NULL;
+              break;
+            }
+          else
+            return -2;
+        }
+
+      if (count == 0)
+        {
+          entries = NULL;
+          break;
+        }
+
+      entries = (aclent_t *) malloc (count * sizeof (aclent_t));
+      if (entries == NULL)
+        {
+          errno = ENOMEM;
+          return -2;
+        }
+
+      if ((source_desc != -1
+           ? facl (source_desc, GETACL, count, entries)
+           : acl (src_name, GETACL, count, entries))
+          == count)
+        break;
+      /* Huh? The number of ACL entries changed since the last call.
+         Repeat.  */
+    }
+
+  /* Is there an ACL of either kind?  */
+# ifdef ACE_GETACL
+  if (ace_count == 0)
+# endif
+    if (count == 0)
+      return qset_acl (dst_name, dest_desc, mode);
+
+  did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
+  saved_errno = 0; /* the first non-ignorable error code */
+
+  if (!MODE_INSIDE_ACL)
+    {
+      /* On Cygwin, it is necessary to call chmod before acl, because
+         chmod can change the contents of the ACL (in ways that don't
+         change the allowed accesses, but still visible).  */
+      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
+        saved_errno = errno;
+      did_chmod = 1;
+    }
+
+  /* If both ace_entries and entries are available, try SETACL before
+     ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
+     can.  */
+
+  if (count > 0)
+    {
+      ret = (dest_desc != -1
+             ? facl (dest_desc, SETACL, count, entries)
+             : acl (dst_name, SETACL, count, entries));
+      if (ret < 0 && saved_errno == 0)
+        {
+          saved_errno = errno;
+          if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
+              && !acl_nontrivial (count, entries))
+            saved_errno = 0;
+        }
+      else
+        did_chmod = 1;
+    }
+  free (entries);
+
+# ifdef ACE_GETACL
+  if (ace_count > 0)
+    {
+      ret = (dest_desc != -1
+             ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries)
+             : acl (dst_name, ACE_SETACL, ace_count, ace_entries));
+      if (ret < 0 && saved_errno == 0)
+        {
+          saved_errno = errno;
+          if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
+              && !acl_ace_nontrivial (ace_count, ace_entries))
+            saved_errno = 0;
+        }
+    }
+  free (ace_entries);
+# endif
+
+  if (MODE_INSIDE_ACL
+      && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
+    {
+      /* We did not call chmod so far, and either the mode and the ACL are
+         separate or special bits are to be set which don't fit into ACLs.  */
+
+      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
+        {
+          if (saved_errno == 0)
+            saved_errno = errno;
+        }
+    }
+
+  if (saved_errno)
+    {
+      errno = saved_errno;
+      return -1;
+    }
+  return 0;
+
+#elif USE_ACL && HAVE_GETACL /* HP-UX */
+
+  struct acl_entry entries[NACLENTRIES];
+  int count;
+# if HAVE_ACLV_H
+  struct acl aclv_entries[NACLVENTRIES];
+  int aclv_count;
+# endif
+  int did_chmod;
+  int saved_errno;
+  int ret;
+
+  count = (source_desc != -1
+           ? fgetacl (source_desc, NACLENTRIES, entries)
+           : getacl (src_name, NACLENTRIES, entries));
+
+  if (count < 0)
+    {
+      if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
+        count = 0;
+      else
+        return -2;
+    }
+  else if (count > 0)
+    {
+      if (count > NACLENTRIES)
+        /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
+        abort ();
+    }
+
+# if HAVE_ACLV_H
+  aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries);
+
+  if (aclv_count < 0)
+    {
+      if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
+        count = 0;
+      else
+        return -2;
+    }
+  else if (aclv_count > 0)
+    {
+      if (aclv_count > NACLVENTRIES)
+        /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation.  */
+        abort ();
+    }
+# endif
+
+  if (count == 0)
+# if HAVE_ACLV_H
+    if (aclv_count == 0)
+# endif
+      return qset_acl (dst_name, dest_desc, mode);
+
+  did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
+  saved_errno = 0; /* the first non-ignorable error code */
+
+  if (count > 0)
+    {
+      ret = (dest_desc != -1
+             ? fsetacl (dest_desc, count, entries)
+             : setacl (dst_name, count, entries));
+      if (ret < 0 && saved_errno == 0)
+        {
+          saved_errno = errno;
+          if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
+            {
+              struct stat source_statbuf;
+
+              if ((source_desc != -1
+                   ? fstat (source_desc, &source_statbuf)
+                   : stat (src_name, &source_statbuf)) == 0)
+                {
+                  if (!acl_nontrivial (count, entries, &source_statbuf))
+                    saved_errno = 0;
+                }
+              else
+                saved_errno = errno;
+            }
+        }
+      else
+        did_chmod = 1;
+    }
+
+# if HAVE_ACLV_H
+  if (aclv_count > 0)
+    {
+      ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries);
+      if (ret < 0 && saved_errno == 0)
+        {
+          saved_errno = errno;
+          if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
+            {
+              if (!aclv_nontrivial (aclv_count, aclv_entries))
+                saved_errno = 0;
+            }
+        }
+      else
+        did_chmod = 1;
+    }
+# endif
+
+  if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
+    {
+      /* We did not call chmod so far, and special bits are to be set which
+         don't fit into ACLs.  */
+
+      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
+        {
+          if (saved_errno == 0)
+            saved_errno = errno;
+        }
+    }
+
+  if (saved_errno)
+    {
+      errno = saved_errno;
+      return -1;
+    }
+  return 0;
+
+#elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
+
+  /* TODO */
+
+#elif USE_ACL && HAVE_STATACL /* older AIX */
+
+  union { struct acl a; char room[4096]; } u;
+  int ret;
+
+  if ((source_desc != -1
+       ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
+       : statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
+      < 0)
+    return -2;
+
+  ret = (dest_desc != -1
+         ? fchacl (dest_desc, &u.a, u.a.acl_len)
+         : chacl (dst_name, &u.a, u.a.acl_len));
+  if (ret < 0)
+    {
+      int saved_errno = errno;
+
+      chmod_or_fchmod (dst_name, dest_desc, mode);
+      errno = saved_errno;
+      return -1;
+    }
+
+  /* No need to call chmod_or_fchmod at this point, since the mode bits
+     S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL.  */
+
+  return 0;
+
+#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
+
+  struct acl entries[NACLENTRIES];
+  int count;
+  int ret;
+
+  count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries);
+
+  if (count < 0)
+    {
+      if (0)
+        count = 0;
+      else
+        return -2;
+    }
+  else if (count > 0)
+    {
+      if (count > NACLENTRIES)
+        /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
+        abort ();
+    }
+
+  if (count == 0)
+    return qset_acl (dst_name, dest_desc, mode);
+
+  ret = acl ((char *) dst_name, ACL_SET, count, entries);
+  if (ret < 0)
+    {
+      int saved_errno = errno;
+
+      if (0)
+        {
+          if (!acl_nontrivial (count, entries))
+            return chmod_or_fchmod (dst_name, dest_desc, mode);
+        }
+
+      chmod_or_fchmod (dst_name, dest_desc, mode);
+      errno = saved_errno;
+      return -1;
+    }
+
+  if (mode & (S_ISUID | S_ISGID | S_ISVTX))
+    {
+      /* We did not call chmod so far, and either the mode and the ACL are
+         separate or special bits are to be set which don't fit into ACLs.  */
+
+      return chmod_or_fchmod (dst_name, dest_desc, mode);
+    }
+  return 0;
+
+#else
+
+  return qset_acl (dst_name, dest_desc, mode);
+
+#endif
+}

=== added file 'lib/qset-acl.c'
--- lib/qset-acl.c	1970-01-01 00:00:00 +0000
+++ lib/qset-acl.c	2013-04-28 00:46:36 +0000
@@ -0,0 +1,676 @@
+/* qset-acl.c - set access control list equivalent to a mode
+
+   Copyright (C) 2002-2003, 2005-2013 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 Paul Eggert and Andreas Gruenbacher, and Bruno Haible.  */
+
+#include <config.h>
+
+#define ACL_INTERNAL_INLINE _GL_EXTERN_INLINE
+
+#include "acl.h"
+
+#include "acl-internal.h"
+
+
+/* If DESC is a valid file descriptor use fchmod to change the
+   file's mode to MODE on systems that have fchmod. On systems
+   that don't have fchmod and if DESC is invalid, use chmod on
+   NAME instead.
+   Return 0 if successful.  Return -1 and set errno upon failure.  */
+
+int
+chmod_or_fchmod (const char *name, int desc, mode_t mode)
+{
+  if (HAVE_FCHMOD && desc != -1)
+    return fchmod (desc, mode);
+  else
+    return chmod (name, mode);
+}
+
+/* Set the access control lists of a file. If DESC is a valid file
+   descriptor, use file descriptor operations where available, else use
+   filename based operations on NAME.  If access control lists are not
+   available, fchmod the target file to MODE.  Also sets the
+   non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
+   to those from MODE if any are set.
+   Return 0 if successful.  Return -1 and set errno upon failure.  */
+
+int
+qset_acl (char const *name, int desc, mode_t mode)
+{
+#if USE_ACL
+# if HAVE_ACL_GET_FILE
+  /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
+  /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
+#  if !HAVE_ACL_TYPE_EXTENDED
+  /* Linux, FreeBSD, IRIX, Tru64 */
+
+  /* We must also have acl_from_text and acl_delete_def_file.
+     (acl_delete_def_file could be emulated with acl_init followed
+      by acl_set_file, but acl_set_file with an empty acl is
+      unspecified.)  */
+
+#   ifndef HAVE_ACL_FROM_TEXT
+#    error Must have acl_from_text (see POSIX 1003.1e draft 17).
+#   endif
+#   ifndef HAVE_ACL_DELETE_DEF_FILE
+#    error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
+#   endif
+
+  acl_t acl;
+  int ret;
+
+  if (HAVE_ACL_FROM_MODE) /* Linux */
+    {
+      acl = acl_from_mode (mode);
+      if (!acl)
+        return -1;
+    }
+  else /* FreeBSD, IRIX, Tru64 */
+    {
+      /* If we were to create the ACL using the functions acl_init(),
+         acl_create_entry(), acl_set_tag_type(), acl_set_qualifier(),
+         acl_get_permset(), acl_clear_perm[s](), acl_add_perm(), we
+         would need to create a qualifier.  I don't know how to do this.
+         So create it using acl_from_text().  */
+
+#   if HAVE_ACL_FREE_TEXT /* Tru64 */
+      char acl_text[] = "u::---,g::---,o::---,";
+#   else /* FreeBSD, IRIX */
+      char acl_text[] = "u::---,g::---,o::---";
+#   endif
+
+      if (mode & S_IRUSR) acl_text[ 3] = 'r';
+      if (mode & S_IWUSR) acl_text[ 4] = 'w';
+      if (mode & S_IXUSR) acl_text[ 5] = 'x';
+      if (mode & S_IRGRP) acl_text[10] = 'r';
+      if (mode & S_IWGRP) acl_text[11] = 'w';
+      if (mode & S_IXGRP) acl_text[12] = 'x';
+      if (mode & S_IROTH) acl_text[17] = 'r';
+      if (mode & S_IWOTH) acl_text[18] = 'w';
+      if (mode & S_IXOTH) acl_text[19] = 'x';
+
+      acl = acl_from_text (acl_text);
+      if (!acl)
+        return -1;
+    }
+  if (HAVE_ACL_SET_FD && desc != -1)
+    ret = acl_set_fd (desc, acl);
+  else
+    ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
+  if (ret != 0)
+    {
+      int saved_errno = errno;
+      acl_free (acl);
+      if (! acl_errno_valid (errno))
+        return chmod_or_fchmod (name, desc, mode);
+      errno = saved_errno;
+      return -1;
+    }
+  else
+    acl_free (acl);
+
+  if (S_ISDIR (mode) && acl_delete_def_file (name))
+    return -1;
+
+  if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
+    {
+      /* We did not call chmod so far, and either the mode and the ACL are
+         separate or special bits are to be set which don't fit into ACLs.  */
+      return chmod_or_fchmod (name, desc, mode);
+    }
+  return 0;
+
+#  else /* HAVE_ACL_TYPE_EXTENDED */
+  /* Mac OS X */
+
+  /* On Mac OS X,  acl_get_file (name, ACL_TYPE_ACCESS)
+     and           acl_get_file (name, ACL_TYPE_DEFAULT)
+     always return NULL / EINVAL.  You have to use
+                   acl_get_file (name, ACL_TYPE_EXTENDED)
+     or            acl_get_fd (open (name, ...))
+     to retrieve an ACL.
+     On the other hand,
+                   acl_set_file (name, ACL_TYPE_ACCESS, acl)
+     and           acl_set_file (name, ACL_TYPE_DEFAULT, acl)
+     have the same effect as
+                   acl_set_file (name, ACL_TYPE_EXTENDED, acl):
+     Each of these calls sets the file's ACL.  */
+
+  acl_t acl;
+  int ret;
+
+  /* Remove the ACL if the file has ACLs.  */
+  if (HAVE_ACL_GET_FD && desc != -1)
+    acl = acl_get_fd (desc);
+  else
+    acl = acl_get_file (name, ACL_TYPE_EXTENDED);
+  if (acl)
+    {
+      acl_free (acl);
+
+      acl = acl_init (0);
+      if (acl)
+        {
+          if (HAVE_ACL_SET_FD && desc != -1)
+            ret = acl_set_fd (desc, acl);
+          else
+            ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
+          if (ret != 0)
+            {
+              int saved_errno = errno;
+              acl_free (acl);
+              if (! acl_errno_valid (saved_errno))
+                return chmod_or_fchmod (name, desc, mode);
+              errno = saved_errno;
+              return -1;
+            }
+          acl_free (acl);
+        }
+    }
+
+  /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly.  */
+  return chmod_or_fchmod (name, desc, mode);
+#  endif
+
+# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
+
+  int done_setacl = 0;
+
+#  ifdef ACE_GETACL
+  /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
+     file systems (whereas the other ones are used in UFS file systems).  */
+
+  /* The flags in the ace_t structure changed in a binary incompatible way
+     when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
+     How to distinguish the two conventions at runtime?
+     We fetch the existing ACL.  In the old convention, usually three ACEs have
+     a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400.
+     In the new convention, these values are not used.  */
+  int convention;
+
+  {
+    /* Initially, try to read the entries into a stack-allocated buffer.
+       Use malloc if it does not fit.  */
+    enum
+      {
+        alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
+        alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
+      };
+    ace_t buf[alloc_init];
+    size_t alloc = alloc_init;
+    ace_t *entries = buf;
+    ace_t *malloced = NULL;
+    int count;
+
+    for (;;)
+      {
+        count = (desc != -1
+                 ? facl (desc, ACE_GETACL, alloc, entries)
+                 : acl (name, ACE_GETACL, alloc, entries));
+        if (count < 0 && errno == ENOSPC)
+          {
+            /* Increase the size of the buffer.  */
+            free (malloced);
+            if (alloc > alloc_max / 2)
+              {
+                errno = ENOMEM;
+                return -1;
+              }
+            alloc = 2 * alloc; /* <= alloc_max */
+            entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
+            if (entries == NULL)
+              {
+                errno = ENOMEM;
+                return -1;
+              }
+            continue;
+          }
+        break;
+      }
+
+    if (count <= 0)
+      convention = -1;
+    else
+      {
+        int i;
+
+        convention = 0;
+        for (i = 0; i < count; i++)
+          if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER))
+            {
+              convention = 1;
+              break;
+            }
+      }
+    free (malloced);
+  }
+
+  if (convention >= 0)
+    {
+      ace_t entries[6];
+      int count;
+      int ret;
+
+      if (convention)
+        {
+          /* Running on Solaris 10.  */
+          entries[0].a_type = OLD_ALLOW;
+          entries[0].a_flags = OLD_ACE_OWNER;
+          entries[0].a_who = 0; /* irrelevant */
+          entries[0].a_access_mask = (mode >> 6) & 7;
+          entries[1].a_type = OLD_ALLOW;
+          entries[1].a_flags = OLD_ACE_GROUP;
+          entries[1].a_who = 0; /* irrelevant */
+          entries[1].a_access_mask = (mode >> 3) & 7;
+          entries[2].a_type = OLD_ALLOW;
+          entries[2].a_flags = OLD_ACE_OTHER;
+          entries[2].a_who = 0;
+          entries[2].a_access_mask = mode & 7;
+          count = 3;
+        }
+      else
+        {
+          /* Running on Solaris 10 (newer version) or Solaris 11.
+             The details here were found through "/bin/ls -lvd somefiles".  */
+          entries[0].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
+          entries[0].a_flags = NEW_ACE_OWNER;
+          entries[0].a_who = 0; /* irrelevant */
+          entries[0].a_access_mask = 0;
+          entries[1].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
+          entries[1].a_flags = NEW_ACE_OWNER;
+          entries[1].a_who = 0; /* irrelevant */
+          entries[1].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
+                                     | NEW_ACE_WRITE_ATTRIBUTES
+                                     | NEW_ACE_WRITE_ACL
+                                     | NEW_ACE_WRITE_OWNER;
+          if (mode & 0400)
+            entries[1].a_access_mask |= NEW_ACE_READ_DATA;
+          else
+            entries[0].a_access_mask |= NEW_ACE_READ_DATA;
+          if (mode & 0200)
+            entries[1].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
+          else
+            entries[0].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
+          if (mode & 0100)
+            entries[1].a_access_mask |= NEW_ACE_EXECUTE;
+          else
+            entries[0].a_access_mask |= NEW_ACE_EXECUTE;
+          entries[2].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
+          entries[2].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
+          entries[2].a_who = 0; /* irrelevant */
+          entries[2].a_access_mask = 0;
+          entries[3].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
+          entries[3].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
+          entries[3].a_who = 0; /* irrelevant */
+          entries[3].a_access_mask = 0;
+          if (mode & 0040)
+            entries[3].a_access_mask |= NEW_ACE_READ_DATA;
+          else
+            entries[2].a_access_mask |= NEW_ACE_READ_DATA;
+          if (mode & 0020)
+            entries[3].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
+          else
+            entries[2].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
+          if (mode & 0010)
+            entries[3].a_access_mask |= NEW_ACE_EXECUTE;
+          else
+            entries[2].a_access_mask |= NEW_ACE_EXECUTE;
+          entries[4].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
+          entries[4].a_flags = NEW_ACE_EVERYONE;
+          entries[4].a_who = 0;
+          entries[4].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
+                                     | NEW_ACE_WRITE_ATTRIBUTES
+                                     | NEW_ACE_WRITE_ACL
+                                     | NEW_ACE_WRITE_OWNER;
+          entries[5].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
+          entries[5].a_flags = NEW_ACE_EVERYONE;
+          entries[5].a_who = 0;
+          entries[5].a_access_mask = NEW_ACE_READ_NAMED_ATTRS
+                                     | NEW_ACE_READ_ATTRIBUTES
+                                     | NEW_ACE_READ_ACL
+                                     | NEW_ACE_SYNCHRONIZE;
+          if (mode & 0004)
+            entries[5].a_access_mask |= NEW_ACE_READ_DATA;
+          else
+            entries[4].a_access_mask |= NEW_ACE_READ_DATA;
+          if (mode & 0002)
+            entries[5].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
+          else
+            entries[4].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
+          if (mode & 0001)
+            entries[5].a_access_mask |= NEW_ACE_EXECUTE;
+          else
+            entries[4].a_access_mask |= NEW_ACE_EXECUTE;
+          count = 6;
+        }
+      if (desc != -1)
+        ret = facl (desc, ACE_SETACL, count, entries);
+      else
+        ret = acl (name, ACE_SETACL, count, entries);
+      if (ret < 0 && errno != EINVAL && errno != ENOTSUP)
+        {
+          if (errno == ENOSYS)
+            return chmod_or_fchmod (name, desc, mode);
+          return -1;
+        }
+      if (ret == 0)
+        done_setacl = 1;
+    }
+#  endif
+
+  if (!done_setacl)
+    {
+      aclent_t entries[3];
+      int ret;
+
+      entries[0].a_type = USER_OBJ;
+      entries[0].a_id = 0; /* irrelevant */
+      entries[0].a_perm = (mode >> 6) & 7;
+      entries[1].a_type = GROUP_OBJ;
+      entries[1].a_id = 0; /* irrelevant */
+      entries[1].a_perm = (mode >> 3) & 7;
+      entries[2].a_type = OTHER_OBJ;
+      entries[2].a_id = 0;
+      entries[2].a_perm = mode & 7;
+
+      if (desc != -1)
+        ret = facl (desc, SETACL,
+                    sizeof (entries) / sizeof (aclent_t), entries);
+      else
+        ret = acl (name, SETACL,
+                   sizeof (entries) / sizeof (aclent_t), entries);
+      if (ret < 0)
+        {
+          if (errno == ENOSYS || errno == EOPNOTSUPP)
+            return chmod_or_fchmod (name, desc, mode);
+          return -1;
+        }
+    }
+
+  if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
+    {
+      /* We did not call chmod so far, so the special bits have not yet
+         been set.  */
+      return chmod_or_fchmod (name, desc, mode);
+    }
+  return 0;
+
+# elif HAVE_GETACL /* HP-UX */
+
+  struct stat statbuf;
+  int ret;
+
+  if (desc != -1)
+    ret = fstat (desc, &statbuf);
+  else
+    ret = stat (name, &statbuf);
+  if (ret < 0)
+    return -1;
+
+  {
+    struct acl_entry entries[3];
+
+    entries[0].uid = statbuf.st_uid;
+    entries[0].gid = ACL_NSGROUP;
+    entries[0].mode = (mode >> 6) & 7;
+    entries[1].uid = ACL_NSUSER;
+    entries[1].gid = statbuf.st_gid;
+    entries[1].mode = (mode >> 3) & 7;
+    entries[2].uid = ACL_NSUSER;
+    entries[2].gid = ACL_NSGROUP;
+    entries[2].mode = mode & 7;
+
+    if (desc != -1)
+      ret = fsetacl (desc, sizeof (entries) / sizeof (struct acl_entry), entries);
+    else
+      ret = setacl (name, sizeof (entries) / sizeof (struct acl_entry), entries);
+  }
+  if (ret < 0)
+    {
+      if (!(errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
+        return -1;
+
+#  if HAVE_ACLV_H /* HP-UX >= 11.11 */
+      {
+        struct acl entries[4];
+
+        entries[0].a_type = USER_OBJ;
+        entries[0].a_id = 0; /* irrelevant */
+        entries[0].a_perm = (mode >> 6) & 7;
+        entries[1].a_type = GROUP_OBJ;
+        entries[1].a_id = 0; /* irrelevant */
+        entries[1].a_perm = (mode >> 3) & 7;
+        entries[2].a_type = CLASS_OBJ;
+        entries[2].a_id = 0;
+        entries[2].a_perm = (mode >> 3) & 7;
+        entries[3].a_type = OTHER_OBJ;
+        entries[3].a_id = 0;
+        entries[3].a_perm = mode & 7;
+
+        ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
+        if (ret > 0)
+          abort ();
+        if (ret < 0)
+          {
+            if (0)
+              return chmod_or_fchmod (name, desc, mode);
+            return -1;
+          }
+
+        ret = acl ((char *) name, ACL_SET,
+                   sizeof (entries) / sizeof (struct acl), entries);
+        if (ret < 0)
+          {
+            if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
+              return chmod_or_fchmod (name, desc, mode);
+            return -1;
+          }
+      }
+#  else
+      return chmod_or_fchmod (name, desc, mode);
+#  endif
+    }
+
+  if (mode & (S_ISUID | S_ISGID | S_ISVTX))
+    {
+      /* We did not call chmod so far, so the special bits have not yet
+         been set.  */
+      return chmod_or_fchmod (name, desc, mode);
+    }
+  return 0;
+
+# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
+
+  acl_type_list_t types;
+  size_t types_size = sizeof (types);
+  acl_type_t type;
+
+  if (aclx_gettypes (name, &types, &types_size) < 0
+      || types.num_entries == 0)
+    return chmod_or_fchmod (name, desc, mode);
+
+  /* XXX Do we need to clear all types of ACLs for the given file, or is it
+     sufficient to clear the first one?  */
+  type = types.entries[0];
+  if (type.u64 == ACL_AIXC)
+    {
+      union { struct acl a; char room[128]; } u;
+      int ret;
+
+      u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */
+      u.a.acl_mode = mode & ~(S_IXACL | 0777);
+      u.a.u_access = (mode >> 6) & 7;
+      u.a.g_access = (mode >> 3) & 7;
+      u.a.o_access = mode & 7;
+
+      if (desc != -1)
+        ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS,
+                         type, &u.a, u.a.acl_len, mode);
+      else
+        ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS,
+                        type, &u.a, u.a.acl_len, mode);
+      if (!(ret < 0 && errno == ENOSYS))
+        return ret;
+    }
+  else if (type.u64 == ACL_NFS4)
+    {
+      union { nfs4_acl_int_t a; char room[128]; } u;
+      nfs4_ace_int_t *ace;
+      int ret;
+
+      u.a.aclVersion = NFS4_ACL_INT_STRUCT_VERSION;
+      u.a.aclEntryN = 0;
+      ace = &u.a.aclEntry[0];
+      {
+        ace->flags = ACE4_ID_SPECIAL;
+        ace->aceWho.special_whoid = ACE4_WHO_OWNER;
+        ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
+        ace->aceFlags = 0;
+        ace->aceMask =
+          (mode & 0400 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
+          | (mode & 0200
+             ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
+               | ACE4_ADD_SUBDIRECTORY
+             : 0)
+          | (mode & 0100 ? ACE4_EXECUTE : 0);
+        ace->aceWhoString[0] = '\0';
+        ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
+        ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
+        u.a.aclEntryN++;
+      }
+      {
+        ace->flags = ACE4_ID_SPECIAL;
+        ace->aceWho.special_whoid = ACE4_WHO_GROUP;
+        ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
+        ace->aceFlags = 0;
+        ace->aceMask =
+          (mode & 0040 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
+          | (mode & 0020
+             ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
+               | ACE4_ADD_SUBDIRECTORY
+             : 0)
+          | (mode & 0010 ? ACE4_EXECUTE : 0);
+        ace->aceWhoString[0] = '\0';
+        ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
+        ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
+        u.a.aclEntryN++;
+      }
+      {
+        ace->flags = ACE4_ID_SPECIAL;
+        ace->aceWho.special_whoid = ACE4_WHO_EVERYONE;
+        ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
+        ace->aceFlags = 0;
+        ace->aceMask =
+          (mode & 0004 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
+          | (mode & 0002
+             ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
+               | ACE4_ADD_SUBDIRECTORY
+             : 0)
+          | (mode & 0001 ? ACE4_EXECUTE : 0);
+        ace->aceWhoString[0] = '\0';
+        ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
+        ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
+        u.a.aclEntryN++;
+      }
+      u.a.aclLength = (char *) ace - (char *) &u.a;
+
+      if (desc != -1)
+        ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS,
+                         type, &u.a, u.a.aclLength, mode);
+      else
+        ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS,
+                        type, &u.a, u.a.aclLength, mode);
+      if (!(ret < 0 && errno == ENOSYS))
+        return ret;
+    }
+
+  return chmod_or_fchmod (name, desc, mode);
+
+# elif HAVE_STATACL /* older AIX */
+
+  union { struct acl a; char room[128]; } u;
+  int ret;
+
+  u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */
+  u.a.acl_mode = mode & ~(S_IXACL | 0777);
+  u.a.u_access = (mode >> 6) & 7;
+  u.a.g_access = (mode >> 3) & 7;
+  u.a.o_access = mode & 7;
+
+  if (desc != -1)
+    ret = fchacl (desc, &u.a, u.a.acl_len);
+  else
+    ret = chacl (name, &u.a, u.a.acl_len);
+
+  if (ret < 0 && errno == ENOSYS)
+    return chmod_or_fchmod (name, desc, mode);
+
+  return ret;
+
+# elif HAVE_ACLSORT /* NonStop Kernel */
+
+  struct acl entries[4];
+  int ret;
+
+  entries[0].a_type = USER_OBJ;
+  entries[0].a_id = 0; /* irrelevant */
+  entries[0].a_perm = (mode >> 6) & 7;
+  entries[1].a_type = GROUP_OBJ;
+  entries[1].a_id = 0; /* irrelevant */
+  entries[1].a_perm = (mode >> 3) & 7;
+  entries[2].a_type = CLASS_OBJ;
+  entries[2].a_id = 0;
+  entries[2].a_perm = (mode >> 3) & 7;
+  entries[3].a_type = OTHER_OBJ;
+  entries[3].a_id = 0;
+  entries[3].a_perm = mode & 7;
+
+  ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries);
+  if (ret > 0)
+    abort ();
+  if (ret < 0)
+    {
+      if (0)
+        return chmod_or_fchmod (name, desc, mode);
+      return -1;
+    }
+
+  ret = acl ((char *) name, ACL_SET,
+             sizeof (entries) / sizeof (struct acl), entries);
+  if (ret < 0)
+    {
+      if (0)
+        return chmod_or_fchmod (name, desc, mode);
+      return -1;
+    }
+
+  if (mode & (S_ISUID | S_ISGID | S_ISVTX))
+    {
+      /* We did not call chmod so far, so the special bits have not yet
+         been set.  */
+      return chmod_or_fchmod (name, desc, mode);
+    }
+  return 0;
+
+# else /* Unknown flavor of ACLs */
+  return chmod_or_fchmod (name, desc, mode);
+# endif
+#else /* !USE_ACL */
+  return chmod_or_fchmod (name, desc, mode);
+#endif
+}

=== added file 'm4/acl.m4'
--- m4/acl.m4	1970-01-01 00:00:00 +0000
+++ m4/acl.m4	2013-04-17 05:21:33 +0000
@@ -0,0 +1,164 @@
+# acl.m4 - check for access control list (ACL) primitives
+# serial 15
+
+# Copyright (C) 2002, 2004-2013 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Written by Paul Eggert and Jim Meyering.
+
+AC_DEFUN([gl_FUNC_ACL],
+[
+  AC_ARG_ENABLE([acl],
+    AS_HELP_STRING([--disable-acl], [do not support ACLs]),
+    , [enable_acl=auto])
+
+  LIB_ACL=
+  use_acl=0
+  if test "x$enable_acl" != "xno"; then
+    dnl On all platforms, the ACL related API is declared in <sys/acl.h>.
+    AC_CHECK_HEADERS([sys/acl.h])
+    if test $ac_cv_header_sys_acl_h = yes; then
+      ac_save_LIBS=$LIBS
+
+      dnl Test for POSIX-draft-like API (Linux, FreeBSD, Mac OS X, IRIX, Tru64).
+      dnl -lacl is needed on Linux, -lpacl is needed on OSF/1.
+      if test $use_acl = 0; then
+        AC_SEARCH_LIBS([acl_get_file], [acl pacl],
+          [if test "$ac_cv_search_acl_get_file" != "none required"; then
+             LIB_ACL=$ac_cv_search_acl_get_file
+           fi
+           AC_CHECK_FUNCS(
+             [acl_get_file acl_get_fd acl_set_file acl_set_fd \
+              acl_free acl_from_mode acl_from_text \
+              acl_delete_def_file acl_extended_file \
+              acl_delete_fd_np acl_delete_file_np \
+              acl_copy_ext_native acl_create_entry_np \
+              acl_to_short_text acl_free_text])
+           # If the acl_get_file bug is detected, don't enable the ACL support.
+           gl_ACL_GET_FILE([use_acl=1], [])
+           if test $use_acl = 1; then
+             dnl On Linux, additional API is declared in <acl/libacl.h>.
+             AC_CHECK_HEADERS([acl/libacl.h])
+             AC_REPLACE_FUNCS([acl_entries])
+             AC_CACHE_CHECK([for ACL_FIRST_ENTRY],
+               [gl_cv_acl_ACL_FIRST_ENTRY],
+               [AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[[#include <sys/types.h>
+#include <sys/acl.h>
+int type = ACL_FIRST_ENTRY;]])],
+                  [gl_cv_acl_ACL_FIRST_ENTRY=yes],
+                  [gl_cv_acl_ACL_FIRST_ENTRY=no])])
+             if test $gl_cv_acl_ACL_FIRST_ENTRY = yes; then
+               AC_DEFINE([HAVE_ACL_FIRST_ENTRY], [1],
+                 [Define to 1 if the constant ACL_FIRST_ENTRY exists.])
+             fi
+             dnl On Mac OS X, other types of ACLs are supported.
+             AC_CACHE_CHECK([for ACL_TYPE_EXTENDED],
+               [gl_cv_acl_ACL_TYPE_EXTENDED],
+               [AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[[#include <sys/types.h>
+#include <sys/acl.h>
+int type = ACL_TYPE_EXTENDED;]])],
+                  [gl_cv_acl_ACL_TYPE_EXTENDED=yes],
+                  [gl_cv_acl_ACL_TYPE_EXTENDED=no])])
+             if test $gl_cv_acl_ACL_TYPE_EXTENDED = yes; then
+               AC_DEFINE([HAVE_ACL_TYPE_EXTENDED], [1],
+                 [Define to 1 if the ACL type ACL_TYPE_EXTENDED exists.])
+             fi
+           else
+             LIB_ACL=
+           fi
+          ])
+      fi
+
+      dnl Test for Solaris API (Solaris, Cygwin).
+      if test $use_acl = 0; then
+        AC_CHECK_FUNCS([facl])
+        if test $ac_cv_func_facl = yes; then
+          AC_SEARCH_LIBS([acl_trivial], [sec],
+            [if test "$ac_cv_search_acl_trivial" != "none required"; then
+               LIB_ACL=$ac_cv_search_acl_trivial
+             fi
+            ])
+          AC_CHECK_FUNCS([acl_trivial])
+          use_acl=1
+        fi
+      fi
+
+      dnl Test for HP-UX API.
+      if test $use_acl = 0; then
+        AC_CHECK_FUNCS([getacl])
+        if test $ac_cv_func_getacl = yes; then
+          use_acl=1
+        fi
+        dnl Test for HP-UX 11.11 API.
+        AC_CHECK_HEADERS([aclv.h], [], [], [#include <sys/types.h>])
+      fi
+
+      dnl Test for AIX API (AIX 5.3 or newer).
+      if test $use_acl = 0; then
+        AC_CHECK_FUNCS([aclx_get])
+        if test $ac_cv_func_aclx_get = yes; then
+          use_acl=1
+        fi
+      fi
+
+      dnl Test for older AIX API.
+      if test $use_acl = 0 || test "$ac_cv_func_aclx_get" = yes; then
+        AC_CHECK_FUNCS([statacl])
+        if test $ac_cv_func_statacl = yes; then
+          use_acl=1
+        fi
+      fi
+
+      dnl Test for NonStop Kernel API.
+      if test $use_acl = 0; then
+        AC_CHECK_FUNCS([aclsort])
+        if test $ac_cv_func_aclsort = yes; then
+          use_acl=1
+        fi
+      fi
+
+      LIBS=$ac_save_LIBS
+    fi
+    if test "x$enable_acl$use_acl" = "xyes0"; then
+      AC_MSG_ERROR([ACLs enabled but support not detected])
+    elif test "x$enable_acl$use_acl" = "xauto0"; then
+      AC_MSG_WARN([libacl development library was not found or not usable.])
+      AC_MSG_WARN([AC_PACKAGE_NAME will be built without ACL support.])
+    fi
+  fi
+  AC_SUBST([LIB_ACL])
+  AC_DEFINE_UNQUOTED([USE_ACL], [$use_acl],
+    [Define to nonzero if you want access control list support.])
+  USE_ACL=$use_acl
+  AC_SUBST([USE_ACL])
+])
+
+# gl_ACL_GET_FILE(IF-WORKS, IF-NOT)
+# -------------------------------------
+# If 'acl_get_file' works (does not have a particular bug),
+# run IF-WORKS, otherwise, IF-NOT.
+# This tests for a Darwin 8.7.0 bug, whereby acl_get_file returns NULL,
+# but sets errno = ENOENT for an existing file or directory.
+AC_DEFUN([gl_ACL_GET_FILE],
+[
+  AC_CACHE_CHECK([for working acl_get_file], [gl_cv_func_working_acl_get_file],
+    [AC_RUN_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <sys/types.h>
+           #include <sys/acl.h>
+           #include <errno.h>
+          ]],
+          [[if (!acl_get_file (".", ACL_TYPE_ACCESS) && errno == ENOENT)
+              return 1;
+            return 0;
+          ]])],
+       [gl_cv_func_working_acl_get_file=yes],
+       [gl_cv_func_working_acl_get_file=no],
+       [gl_cv_func_working_acl_get_file=cross-compiling])])
+
+  AS_IF([test $gl_cv_func_working_acl_get_file = yes], [$1], [$2])
+])

=== modified file 'm4/gnulib-comp.m4'
--- m4/gnulib-comp.m4	2013-03-13 18:42:22 +0000
+++ m4/gnulib-comp.m4	2013-04-27 20:24:10 +0000
@@ -94,6 +94,7 @@
   # Code from module pselect:
   # Code from module pthread_sigmask:
   # Code from module putenv:
+  # Code from module qacl:
   # Code from module readlink:
   # Code from module readlinkat:
   # Code from module root-uid:
@@ -287,6 +288,7 @@
     gl_PREREQ_PUTENV
   fi
   gl_STDLIB_MODULE_INDICATOR([putenv])
+  gl_FUNC_ACL
   gl_FUNC_READLINK
   if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then
     AC_LIBOBJ([readlink])
@@ -733,6 +735,10 @@
   build-aux/snippet/arg-nonnull.h
   build-aux/snippet/c++defs.h
   build-aux/snippet/warn-on-use.h
+  lib/acl-errno-valid.c
+  lib/acl-internal.h
+  lib/acl.h
+  lib/acl_entries.c
   lib/alloca.in.h
   lib/allocator.c
   lib/allocator.h
@@ -758,6 +764,7 @@
   lib/fcntl.in.h
   lib/fdatasync.c
   lib/fdopendir.c
+  lib/file-has-acl.c
   lib/filemode.c
   lib/filemode.h
   lib/fpending.c
@@ -792,6 +799,8 @@
   lib/pselect.c
   lib/pthread_sigmask.c
   lib/putenv.c
+  lib/qcopy-acl.c
+  lib/qset-acl.c
   lib/readlink.c
   lib/readlinkat.c
   lib/root-uid.h
@@ -843,6 +852,7 @@
   lib/verify.h
   lib/xalloc-oversized.h
   m4/00gnulib.m4
+  m4/acl.m4
   m4/alloca.m4
   m4/c-strtod.m4
   m4/clock_time.m4

=== modified file 'nt/ChangeLog'
--- nt/ChangeLog	2013-04-09 02:38:56 +0000
+++ nt/ChangeLog	2013-04-17 05:21:33 +0000
@@ -1,3 +1,8 @@
+2013-04-17  Paul Eggert  <[email-masked]>
+
+	Use Gnulib ACL implementation, for benefit of Solaris etc.
+	* config.nt (HAVE_ACL_SET_FILE): Rename from HAVE_POSIX_ACL.
+
 2013-04-09  Ken Brown  <[email-masked]>
 
 	* emacs.rc: Use 64-bit manifest for 64-bit Cygwin build.

=== modified file 'nt/config.nt'
--- nt/config.nt	2013-03-30 07:10:58 +0000
+++ nt/config.nt	2013-04-17 05:21:33 +0000
@@ -756,7 +756,7 @@
 #undef HAVE_PNG_H
 
 /* Define to 1 if using POSIX ACL support. */
-#define HAVE_POSIX_ACL 1
+#define HAVE_ACL_SET_FILE 1
 
 /* Define to 1 if you have the `posix_memalign' function. */
 #undef HAVE_POSIX_MEMALIGN

=== modified file 'src/ChangeLog'
--- src/ChangeLog	2013-04-27 21:12:17 +0000
+++ src/ChangeLog	2013-04-28 00:00:19 +0000
@@ -1,3 +1,10 @@
+2013-04-27  Paul Eggert  <[email-masked]>
+
+	Use Gnulib ACL implementation, for benefit of Solaris etc.
+	* Makefile.in (LIB_ACL): New macro.
+	(LIBACL_LIBS): Remove.
+	(LIBES): Use LIB_ACL, not LIBACL_LIBS.
+
 2013-04-27  Juri Linkov  <[email-masked]>
 
 	* callint.c (Fcall_interactively): Call `Qread_number' for

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2013-04-22 05:18:30 +0000
+++ src/Makefile.in	2013-04-27 19:40:49 +0000
@@ -137,6 +137,7 @@
 M17N_FLT_CFLAGS = @M17N_FLT_CFLAGS@
 M17N_FLT_LIBS = @M17N_FLT_LIBS@
 
+LIB_ACL=@LIB_ACL@
 LIB_CLOCK_GETTIME=@LIB_CLOCK_GETTIME@
 LIB_EACCESS=@LIB_EACCESS@
 LIB_FDATASYNC=@LIB_FDATASYNC@
@@ -282,8 +283,6 @@
 LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
 LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
 
-LIBACL_LIBS = @LIBACL_LIBS@
-
 LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@
 
 INTERVALS_H = dispextern.h intervals.h composite.h
@@ -391,13 +390,13 @@
 ## Construct full set of libraries to be linked.
 LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
    $(LIBX_OTHER) $(LIBSOUND) \
-   $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_CLOCK_GETTIME) \
+   $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(LIB_CLOCK_GETTIME) \
    $(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
    $(LIB_EXECINFO) \
    $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
-   $(LIBACL_LIBS) $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(LIB_PTHREAD_SIGMASK) \
+   $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(LIB_PTHREAD_SIGMASK) \
    $(LIB_MATH)
 
 all: emacs$(EXEEXT) $(OTHER_FILES)

=== modified file 'src/fileio.c'
--- src/fileio.c	2013-04-07 16:18:41 +0000
+++ src/fileio.c	2013-04-17 05:21:33 +0000
@@ -36,7 +36,7 @@
 #include <selinux/context.h>
 #endif
 
-#ifdef HAVE_POSIX_ACL
+#ifdef HAVE_ACL_SET_FILE
 #include <sys/acl.h>
 #endif
 
@@ -81,26 +81,8 @@
 #define DRIVE_LETTER(x) c_tolower (x)
 #endif
 
-#ifdef HAVE_POSIX_ACL
-/* FIXME: this macro was copied from gnulib's private acl-internal.h
-   header file.  */
-/* Recognize some common errors such as from an NFS mount that does
-   not support ACLs, even when local drives do.  */
-#if defined __APPLE__ && defined __MACH__ /* Mac OS X */
-#define ACL_NOT_WELL_SUPPORTED(Err)					\
-  ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY || (Err) == ENOENT)
-#elif defined EOPNOTSUPP /* Tru64 NFS */
-#define ACL_NOT_WELL_SUPPORTED(Err)					\
-  ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY || (Err) == EOPNOTSUPP)
-#elif defined WINDOWSNT
-#define ACL_NOT_WELL_SUPPORTED(Err)  ((Err) == ENOTSUP)
-#else
-#define ACL_NOT_WELL_SUPPORTED(Err)					\
-  ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY)
-#endif
-#endif	/* HAVE_POSIX_ACL */
-
 #include "systime.h"
+#include <acl.h>
 #include <allocator.h>
 #include <careadlinkat.h>
 #include <stat-time.h>
@@ -1988,9 +1970,6 @@
   security_context_t con;
   int conlength = 0;
 #endif
-#ifdef HAVE_POSIX_ACL
-  acl_t acl = NULL;
-#endif
 
   encoded_file = encoded_newname = Qnil;
   GCPRO4 (file, newname, encoded_file, encoded_newname);
@@ -2026,14 +2005,6 @@
     out_st.st_mode = 0;
 
 #ifdef WINDOWSNT
-  if (!NILP (preserve_extended_attributes))
-    {
-#ifdef HAVE_POSIX_ACL
-      acl = acl_get_file (SDATA (encoded_file), ACL_TYPE_ACCESS);
-      if (acl == NULL && !ACL_NOT_WELL_SUPPORTED (errno))
-	report_file_error ("Getting ACL", Fcons (file, Qnil));
-#endif
-    }
   if (!CopyFile (SDATA (encoded_file),
 		 SDATA (encoded_newname),
 		 FALSE))
@@ -2069,17 +2040,6 @@
       /* Restore original attributes.  */
       SetFileAttributes (filename, attributes);
     }
-#ifdef HAVE_POSIX_ACL
-  if (acl != NULL)
-    {
-      bool fail =
-	acl_set_file (SDATA (encoded_newname), ACL_TYPE_ACCESS, acl) != 0;
-      if (fail && !ACL_NOT_WELL_SUPPORTED (errno))
-	report_file_error ("Setting ACL", Fcons (newname, Qnil));
-
-      acl_free (acl);
-    }
-#endif
 #else /* not WINDOWSNT */
   immediate_quit = 1;
   ifd = emacs_open (SSDATA (encoded_file), O_RDONLY, 0);
@@ -2103,12 +2063,6 @@
 	    report_file_error ("Doing fgetfilecon", Fcons (file, Qnil));
 	}
 #endif
-
-#ifdef HAVE_POSIX_ACL
-      acl = acl_get_fd (ifd);
-      if (acl == NULL && !ACL_NOT_WELL_SUPPORTED (errno))
-	report_file_error ("Getting ACL", Fcons (file, Qnil));
-#endif
     }
 
   if (out_st.st_mode != 0
@@ -2156,7 +2110,7 @@
   immediate_quit = 0;
 
 #ifndef MSDOS
-  /* Preserve the original file modes, and if requested, also its
+  /* Preserve the original file permissions, and if requested, also its
      owner and group.  */
   {
     mode_t mode_mask = 07777;
@@ -2173,8 +2127,16 @@
 	      mode_mask |= 02000;
 	  }
       }
-    if (fchmod (ofd, st.st_mode & mode_mask) != 0)
-      report_file_error ("Doing chmod", Fcons (newname, Qnil));
+
+    switch (!NILP (preserve_extended_attributes)
+	    ? qcopy_acl (SSDATA (encoded_file), ifd,
+			 SSDATA (encoded_newname), ofd,
+			 st.st_mode & mode_mask)
+	    : fchmod (ofd, st.st_mode & mode_mask))
+      {
+      case -2: report_file_error ("Copying permissions from", list1 (file));
+      case -1: report_file_error ("Copying permissions to", list1 (newname));
+      }
   }
 #endif	/* not MSDOS */
 
@@ -2191,17 +2153,6 @@
     }
 #endif
 
-#ifdef HAVE_POSIX_ACL
-  if (acl != NULL)
-    {
-      bool fail = acl_set_fd (ofd, acl) != 0;
-      if (fail && !ACL_NOT_WELL_SUPPORTED (errno))
-	report_file_error ("Setting ACL", Fcons (newname, Qnil));
-
-      acl_free (acl);
-    }
-#endif
-
   if (!NILP (keep_time))
     {
       EMACS_TIME atime = get_stat_atime (&st);
@@ -3111,7 +3062,7 @@
 {
   Lisp_Object absname;
   Lisp_Object handler;
-#ifdef HAVE_POSIX_ACL
+#ifdef HAVE_ACL_SET_FILE
   acl_t acl;
   Lisp_Object acl_string;
   char *str;
@@ -3126,7 +3077,7 @@
   if (!NILP (handler))
     return call2 (handler, Qfile_acl, absname);
 
-#ifdef HAVE_POSIX_ACL
+#ifdef HAVE_ACL_SET_FILE
   absname = ENCODE_FILE (absname);
 
   acl = acl_get_file (SSDATA (absname), ACL_TYPE_ACCESS);
@@ -3164,7 +3115,7 @@
 {
   Lisp_Object absname;
   Lisp_Object handler;
-#ifdef HAVE_POSIX_ACL
+#ifdef HAVE_ACL_SET_FILE
   Lisp_Object encoded_absname;
   acl_t acl;
   bool fail;
@@ -3178,7 +3129,7 @@
   if (!NILP (handler))
     return call3 (handler, Qset_file_acl, absname, acl_string);
 
-#ifdef HAVE_POSIX_ACL
+#ifdef HAVE_ACL_SET_FILE
   if (STRINGP (acl_string))
     {
       acl = acl_from_text (SSDATA (acl_string));
@@ -3193,7 +3144,7 @@
       fail = (acl_set_file (SSDATA (encoded_absname), ACL_TYPE_ACCESS,
 			    acl)
 	      != 0);
-      if (fail && !ACL_NOT_WELL_SUPPORTED (errno))
+      if (fail && acl_errno_valid (errno))
 	report_file_error ("Setting ACL", Fcons (absname, Qnil));
 
       acl_free (acl);