Hi Jim,

Here comes the reworked patch for MacOS X 10.5 support in copy_acl, used
by the 'copy-file' module. With it, now the test passes on MacOS X 10.5,
and of course still passes on Linux and FreeBSD.

The main difficulty here was to realize that in MacOS X, unlike many other
flavors of ACLs, an ACL does *not* contain the file mode (rwxrwxrwx). They
are separate. In the code I created a macro MODE_INSIDE_ACL to denote the
"normal" situation.

The consequences are that
  - The qset_acl function requires a different logic when !MODE_INSIDE_ACL.
    When MODE_INSIDE_ACL, one optimizes system calls by calling chmod only
    when setting the ACL failed or was not enough. When !MODE_INSIDE_ACL,
    one has to call chmod always.
  - Similarly in copy_acl, but here the code changes are smaller.
  - When !MODE_INSIDE_ACL, a trivial ACL has 0 entries, not 3 entries.


Another realization is that this piece of code in acl.c:

      char acl_text[] = "u::---,g::---,o::---";

      if (mode & S_IRUSR) acl_text[ 3] = 'r';
      if (mode & S_IWUSR) acl_text[ 4] = 'w';
      if (mode & S_IXUSR) acl_text[ 5] = 'x';

works only on FreeBSD (and possibly IRIX). Basically, every ACL flavor comes
with its own textual representation of ACLs, and most of them expect the
syntax "other:rwx", not "other::rwx".


Also, I added a comment explaining why the conversion mode_t -> acl_t goes
through the textual representation rather than through acl_init() and
acl_create_entry().


> for future patches to my attention please use git format-patch,
> since that makes it easier for me to apply and ensure that when I review

Find it attached as attachment. Now I'll have to learn how to amend previous
commits...

OK to commit? After this, I'll turn to the other 5 platforms.


2008-05-22  Bruno Haible  <[EMAIL PROTECTED]>

        Make copy_acl work on MacOS X 10.5.
        * lib/acl-internal.h (MODE_INSIDE_ACL): New macro.
        (ACL_NOT_WELL_SUPPORTED): On MacOS X, also handle ENOENT.
        * lib/acl.c (qset_acl): Add different code branch for !MODE_INSIDE_ACL.
        If MODE_INSIDE_ACL, don't assume that every system has the same text
        representation for ACLs as FreeBSD.
        * lib/copy-acl.c (copy_acl): Add support for platforms with
        !MODE_INSIDE_ACL.
        * lib/file-has-acl.c (file_has_acl): Likewise.
        * m4/acl.m4 (gl_FUNC_ACL): Test for some functions that are witness
        of FreeBSD or MacOS X, respectively.

*** lib/acl-internal.h.orig     2008-05-23 01:08:01.000000000 +0200
--- lib/acl-internal.h  2008-05-23 00:15:58.000000000 +0200
***************
*** 84,91 ****
  # define acl_from_mode(mode) (NULL)
  #endif
  
! #define ACL_NOT_WELL_SUPPORTED(Err) \
!   ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY)
  
  /* Define a replacement for acl_entries if needed.  */
  #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE && !HAVE_ACL_ENTRIES
--- 84,104 ----
  # 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 /* MacOS X */
! # define MODE_INSIDE_ACL 0
! #else
! # define MODE_INSIDE_ACL 1
! #endif
! 
! #if defined __APPLE__ && defined __MACH__ /* MacOS X */
! # define ACL_NOT_WELL_SUPPORTED(Err) \
!    ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY 
|| (Err) == ENOENT)
! #else
! # define ACL_NOT_WELL_SUPPORTED(Err) \
!    ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY)
! #endif
  
  /* Define a replacement for acl_entries if needed.  */
  #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE && !HAVE_ACL_ENTRIES
*** lib/acl.c.orig      2008-05-23 01:08:01.000000000 +0200
--- lib/acl.c   2008-05-23 00:52:39.000000000 +0200
***************
*** 48,79 ****
  int
  qset_acl (char const *name, int desc, mode_t mode)
  {
! #if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
    /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
  
!   /* We must also have 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)
      {
        acl = acl_from_mode (mode);
        if (!acl)
        return -1;
      }
!   else
      {
        char acl_text[] = "u::---,g::---,o::---";
  
        if (mode & S_IRUSR) acl_text[ 3] = 'r';
--- 48,89 ----
  int
  qset_acl (char const *name, int desc, mode_t mode)
  {
! #if USE_ACL
! # if MODE_INSIDE_ACL
! #  if HAVE_ACL_SET_FILE && HAVE_ACL_FREE
    /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
+   /* 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_DELETE_FD_NP && HAVE_ACL_DELETE_FILE_NP /* FreeBSD */
        char acl_text[] = "u::---,g::---,o::---";
  
        if (mode & S_IRUSR) acl_text[ 3] = 'r';
***************
*** 89,94 ****
--- 99,107 ----
        acl = acl_from_text (acl_text);
        if (!acl)
        return -1;
+ #   else /* Unknown flavor of POSIX-like ACLs */
+       return chmod_or_fchmod (name, desc, mode);
+ #   endif
      }
    if (HAVE_ACL_SET_FD && desc != -1)
      ret = acl_set_fd (desc, acl);
***************
*** 124,133 ****
        return -1;
      }
    return 0;
- #else
- 
- # if USE_ACL && defined ACL_NO_TRIVIAL
  
    /* Solaris 10, with NFSv4 ACLs.  */
    acl_t *aclp;
    char acl_text[] = "user::---,group::---,mask:---,other:---";
--- 137,144 ----
        return -1;
      }
    return 0;
  
+ #  elif defined ACL_NO_TRIVIAL
    /* Solaris 10, with NFSv4 ACLs.  */
    acl_t *aclp;
    char acl_text[] = "user::---,group::---,mask:---,other:---";
***************
*** 158,167 ****
          return acl_result;
        }
      }
- # endif
  
    return chmod_or_fchmod (name, desc, mode);
  
  #endif
  }
  
--- 169,234 ----
          return acl_result;
        }
      }
  
    return chmod_or_fchmod (name, desc, mode);
  
+ #  else /* Unknown flavor of ACLs */
+   return chmod_or_fchmod (name, desc, mode);
+ #  endif
+ # else /* !MODE_INSIDE_ACL */
+ #  if HAVE_ACL_SET_FILE && HAVE_ACL_FREE
+   /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
+   /* MacOS X */
+ 
+   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_ACCESS);
+   if (acl)
+     {
+ #   if HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP /* MacOS X */
+       static const char empty_acl_text[] = "!#acl 1\n";
+ #   else /* Unknown flavor of POSIX-like ACLs */
+ #    error Unknown flavor of POSIX-like ACLs - add support for your platform.
+ #   endif
+ 
+       acl = acl_from_text (empty_acl_text);
+       if (acl)
+       {
+         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_NOT_WELL_SUPPORTED (saved_errno))
+               {
+                 if (chmod_or_fchmod (name, desc, mode) != 0)
+                   saved_errno = errno;
+                 else
+                   return 0;
+               }
+             errno = saved_errno;
+             return -1;
+           }
+       }
+     }
+ 
+   return chmod_or_fchmod (name, desc, mode);
+ #  else /* Unknown flavor of ACLs */
+   return chmod_or_fchmod (name, desc, mode);
+ #  endif
+ # endif
+ #else /* !USE_ACL */
+   return chmod_or_fchmod (name, desc, mode);
  #endif
  }
  
*** lib/copy-acl.c.orig 2008-05-23 01:08:01.000000000 +0200
--- lib/copy-acl.c      2008-05-23 00:54:12.000000000 +0200
***************
*** 40,45 ****
--- 40,46 ----
  
  #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
    /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
+   /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
  
    acl_t acl;
    if (HAVE_ACL_GET_FD && source_desc != -1)
***************
*** 70,81 ****
          int n = acl_entries (acl);
  
          acl_free (acl);
!         /* On most hosts an ACL is trivial if n == 3, and it cannot be
!            less than 3.  On IRIX 6.5 it is also trivial if n == -1.
             For simplicity and safety, assume the ACL is trivial if n <= 3.
             Also see file-has-acl.c for some of the other possibilities;
             it's not clear whether that complexity is needed here.  */
!         if (n <= 3)
            {
              if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
                saved_errno = errno;
--- 71,83 ----
          int n = acl_entries (acl);
  
          acl_free (acl);
!         /* On most hosts with MODE_INSIDE_ACL an ACL is trivial if n == 3,
!            and it cannot be less than 3.  On IRIX 6.5 it is also trivial if
!            n == -1.
             For simplicity and safety, assume the ACL is trivial if n <= 3.
             Also see file-has-acl.c for some of the other possibilities;
             it's not clear whether that complexity is needed here.  */
!         if (n <= 3 * MODE_INSIDE_ACL)
            {
              if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
                saved_errno = errno;
***************
*** 97,106 ****
    else
      acl_free (acl);
  
!   if (mode & (S_ISUID | S_ISGID | S_ISVTX))
      {
!       /* We did not call chmod so far, so the special bits have not yet
!          been set.  */
  
        if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
        {
--- 99,108 ----
    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)
        {
*** lib/file-has-acl.c.orig     2008-05-23 01:08:01.000000000 +0200
--- lib/file-has-acl.c  2008-05-23 00:36:37.000000000 +0200
***************
*** 1,6 ****
  /* Test whether a file has a nontrivial access control list.
  
!    Copyright (C) 2002, 2003, 2005, 2006, 2007 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
--- 1,6 ----
  /* Test whether a file has a nontrivial access control list.
  
!    Copyright (C) 2002-2003, 2005-2008 Free Software Foundation, Inc.
  
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
***************
*** 47,52 ****
--- 47,53 ----
  #elif USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE
  
        /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
+       /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
        int ret;
  
        if (HAVE_ACL_EXTENDED_FILE)
***************
*** 56,62 ****
          acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
          if (acl)
            {
!             ret = (3 < acl_entries (acl));
              acl_free (acl);
              if (ret == 0 && S_ISDIR (sb->st_mode))
                {
--- 57,63 ----
          acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
          if (acl)
            {
!             ret = (3 * MODE_INSIDE_ACL < acl_entries (acl));
              acl_free (acl);
              if (ret == 0 && S_ISDIR (sb->st_mode))
                {
*** m4/acl.m4.orig      2008-05-23 01:08:01.000000000 +0200
--- m4/acl.m4   2008-05-23 00:16:28.000000000 +0200
***************
*** 1,5 ****
  # acl.m4 - check for access control list (ACL) primitives
! # serial 3
  
  # Copyright (C) 2002, 2004-2008 Free Software Foundation, Inc.
  # This file is free software; the Free Software Foundation
--- 1,5 ----
  # acl.m4 - check for access control list (ACL) primitives
! # serial 4
  
  # Copyright (C) 2002, 2004-2008 Free Software Foundation, Inc.
  # This file is free software; the Free Software Foundation
***************
*** 35,41 ****
              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])
              if test $ac_cv_func_acl_get_file = yes; then
                # If the acl_get_file bug is detected, disable all ACL support.
                gl_ACL_GET_FILE( , [use_acl=0])
--- 35,43 ----
              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])
              if test $ac_cv_func_acl_get_file = yes; then
                # If the acl_get_file bug is detected, disable all ACL support.
                gl_ACL_GET_FILE( , [use_acl=0])
From da9fd677c05325560fa533cbf7c3e67eb9844fbe Mon Sep 17 00:00:00 2001
From: Bruno Haible <[EMAIL PROTECTED]>
Date: Fri, 23 May 2008 01:13:51 +0200
Subject: [PATCH] Make copy_acl work on MacOS X 10.5.

---
 ChangeLog          |   14 ++++++++
 lib/acl-internal.h |   17 ++++++++-
 lib/acl.c          |   95 ++++++++++++++++++++++++++++++++++++++++++++--------
 lib/copy-acl.c     |   14 ++++---
 lib/file-has-acl.c |    5 ++-
 m4/acl.m4          |    6 ++-
 6 files changed, 125 insertions(+), 26 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9bbd1e9..a2aef6a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2008-05-22  Bruno Haible  <[EMAIL PROTECTED]>
 
+	Make copy_acl work on MacOS X 10.5.
+	* lib/acl-internal.h (MODE_INSIDE_ACL): New macro.
+	(ACL_NOT_WELL_SUPPORTED): On MacOS X, also handle ENOENT.
+	* lib/acl.c (qset_acl): Add different code branch for !MODE_INSIDE_ACL.
+	If MODE_INSIDE_ACL, don't assume that every system has the same text
+	representation for ACLs as FreeBSD.
+	* lib/copy-acl.c (copy_acl): Add support for platforms with
+	!MODE_INSIDE_ACL.
+	* lib/file-has-acl.c (file_has_acl): Likewise.
+	* m4/acl.m4 (gl_FUNC_ACL): Test for some functions that are witness
+	of FreeBSD or MacOS X, respectively.
+
+2008-05-22  Bruno Haible  <[EMAIL PROTECTED]>
+
 	* lib/acl.h: Don't include <sys/acl.h>.
 	(GETACLCNT): Move fallback to lib/acl-internal.h.
 	* lib/acl-internal.h: Include <sys/acl.h> here.
diff --git a/lib/acl-internal.h b/lib/acl-internal.h
index c23d6f4..75bca17 100644
--- a/lib/acl-internal.h
+++ b/lib/acl-internal.h
@@ -84,8 +84,21 @@
 # define acl_from_mode(mode) (NULL)
 #endif
 
-#define ACL_NOT_WELL_SUPPORTED(Err) \
-  ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY)
+/* 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 /* MacOS X */
+# define MODE_INSIDE_ACL 0
+#else
+# define MODE_INSIDE_ACL 1
+#endif
+
+#if defined __APPLE__ && defined __MACH__ /* MacOS X */
+# define ACL_NOT_WELL_SUPPORTED(Err) \
+   ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY || (Err) == ENOENT)
+#else
+# define ACL_NOT_WELL_SUPPORTED(Err) \
+   ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY)
+#endif
 
 /* Define a replacement for acl_entries if needed.  */
 #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE && !HAVE_ACL_ENTRIES
diff --git a/lib/acl.c b/lib/acl.c
index 10499a0..7655d1b 100644
--- a/lib/acl.c
+++ b/lib/acl.c
@@ -48,32 +48,42 @@ chmod_or_fchmod (const char *name, int desc, mode_t mode)
 int
 qset_acl (char const *name, int desc, mode_t mode)
 {
-#if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
+#if USE_ACL
+# if MODE_INSIDE_ACL
+#  if HAVE_ACL_SET_FILE && HAVE_ACL_FREE
   /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
+  /* Linux, FreeBSD, IRIX, Tru64 */
 
-  /* We must also have have_acl_from_text and acl_delete_def_file.
+  /* 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
+#   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)
+  if (HAVE_ACL_FROM_MODE) /* Linux */
     {
       acl = acl_from_mode (mode);
       if (!acl)
 	return -1;
     }
-  else
+  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_DELETE_FD_NP && HAVE_ACL_DELETE_FILE_NP /* FreeBSD */
       char acl_text[] = "u::---,g::---,o::---";
 
       if (mode & S_IRUSR) acl_text[ 3] = 'r';
@@ -89,6 +99,9 @@ qset_acl (char const *name, int desc, mode_t mode)
       acl = acl_from_text (acl_text);
       if (!acl)
 	return -1;
+#   else /* Unknown flavor of POSIX-like ACLs */
+      return chmod_or_fchmod (name, desc, mode);
+#   endif
     }
   if (HAVE_ACL_SET_FD && desc != -1)
     ret = acl_set_fd (desc, acl);
@@ -124,10 +137,8 @@ qset_acl (char const *name, int desc, mode_t mode)
 	return -1;
     }
   return 0;
-#else
-
-# if USE_ACL && defined ACL_NO_TRIVIAL
 
+#  elif defined ACL_NO_TRIVIAL
   /* Solaris 10, with NFSv4 ACLs.  */
   acl_t *aclp;
   char acl_text[] = "user::---,group::---,mask:---,other:---";
@@ -158,10 +169,66 @@ qset_acl (char const *name, int desc, mode_t mode)
 	  return acl_result;
 	}
     }
-# endif
 
   return chmod_or_fchmod (name, desc, mode);
 
+#  else /* Unknown flavor of ACLs */
+  return chmod_or_fchmod (name, desc, mode);
+#  endif
+# else /* !MODE_INSIDE_ACL */
+#  if HAVE_ACL_SET_FILE && HAVE_ACL_FREE
+  /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
+  /* MacOS X */
+
+  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_ACCESS);
+  if (acl)
+    {
+#   if HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP /* MacOS X */
+      static const char empty_acl_text[] = "!#acl 1\n";
+#   else /* Unknown flavor of POSIX-like ACLs */
+#    error Unknown flavor of POSIX-like ACLs - add support for your platform.
+#   endif
+
+      acl = acl_from_text (empty_acl_text);
+      if (acl)
+	{
+	  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_NOT_WELL_SUPPORTED (saved_errno))
+		{
+		  if (chmod_or_fchmod (name, desc, mode) != 0)
+		    saved_errno = errno;
+		  else
+		    return 0;
+		}
+	      errno = saved_errno;
+	      return -1;
+	    }
+	}
+    }
+
+  return chmod_or_fchmod (name, desc, mode);
+#  else /* Unknown flavor of ACLs */
+  return chmod_or_fchmod (name, desc, mode);
+#  endif
+# endif
+#else /* !USE_ACL */
+  return chmod_or_fchmod (name, desc, mode);
 #endif
 }
 
diff --git a/lib/copy-acl.c b/lib/copy-acl.c
index f5a879d..97d2087 100644
--- a/lib/copy-acl.c
+++ b/lib/copy-acl.c
@@ -40,6 +40,7 @@ copy_acl (const char *src_name, int source_desc, const char *dst_name,
 
 #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
   /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
+  /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
 
   acl_t acl;
   if (HAVE_ACL_GET_FD && source_desc != -1)
@@ -70,12 +71,13 @@ copy_acl (const char *src_name, int source_desc, const char *dst_name,
 	  int n = acl_entries (acl);
 
 	  acl_free (acl);
-	  /* On most hosts an ACL is trivial if n == 3, and it cannot be
-	     less than 3.  On IRIX 6.5 it is also trivial if n == -1.
+	  /* On most hosts with MODE_INSIDE_ACL an ACL is trivial if n == 3,
+	     and it cannot be less than 3.  On IRIX 6.5 it is also trivial if
+	     n == -1.
 	     For simplicity and safety, assume the ACL is trivial if n <= 3.
 	     Also see file-has-acl.c for some of the other possibilities;
 	     it's not clear whether that complexity is needed here.  */
-	  if (n <= 3)
+	  if (n <= 3 * MODE_INSIDE_ACL)
 	    {
 	      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
 		saved_errno = errno;
@@ -97,10 +99,10 @@ copy_acl (const char *src_name, int source_desc, const char *dst_name,
   else
     acl_free (acl);
 
-  if (mode & (S_ISUID | S_ISGID | S_ISVTX))
+  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.  */
+      /* 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)
 	{
diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c
index c9786e6..c69d012 100644
--- a/lib/file-has-acl.c
+++ b/lib/file-has-acl.c
@@ -1,6 +1,6 @@
 /* Test whether a file has a nontrivial access control list.
 
-   Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2002-2003, 2005-2008 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -47,6 +47,7 @@ file_has_acl (char const *name, struct stat const *sb)
 #elif USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE
 
       /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
+      /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
       int ret;
 
       if (HAVE_ACL_EXTENDED_FILE)
@@ -56,7 +57,7 @@ file_has_acl (char const *name, struct stat const *sb)
 	  acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
 	  if (acl)
 	    {
-	      ret = (3 < acl_entries (acl));
+	      ret = (3 * MODE_INSIDE_ACL < acl_entries (acl));
 	      acl_free (acl);
 	      if (ret == 0 && S_ISDIR (sb->st_mode))
 		{
diff --git a/m4/acl.m4 b/m4/acl.m4
index 2916a00..72d4b4a 100644
--- a/m4/acl.m4
+++ b/m4/acl.m4
@@ -1,5 +1,5 @@
 # acl.m4 - check for access control list (ACL) primitives
-# serial 3
+# serial 4
 
 # Copyright (C) 2002, 2004-2008 Free Software Foundation, Inc.
 # This file is free software; the Free Software Foundation
@@ -35,7 +35,9 @@ AC_DEFUN([gl_FUNC_ACL],
 	      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_def_file acl_extended_file \
+		 acl_delete_fd_np acl_delete_file_np \
+		 acl_copy_ext_native acl_create_entry_np])
 	      if test $ac_cv_func_acl_get_file = yes; then
 		# If the acl_get_file bug is detected, disable all ACL support.
 		gl_ACL_GET_FILE( , [use_acl=0])
-- 
1.5.4.1

Reply via email to