changeset 15566:8339ac6126c5

acl: Improve support of NFSv4 ACLs on Solaris 10 (newer version). * lib/acl-internal.h (ACE_*, NEW_ACE_*): Define also on newer Solaris 10. (OLD_ALLOW, OLD_DENY): New macros. (NEW_ACE_ACCESS_ALLOWED_ACE_TYPE): Renamed from ACE_ACCESS_ALLOWED_ACE_TYPE. (NEW_ACE_ACCESS_DENIED_ACE_TYPE): Renamed from ACE_ACCESS_DENIED_ACE_TYPE. (OLD_ACE_OWNER, OLD_ACE_GROUP, OLD_ACE_OTHER): New macros. (NEW_ACE_EXECUTE): Fix value. (NEW_ACE_APPEND_DATA, NEW_ACE_READ_NAMED_ATTRS, NEW_ACE_WRITE_NAMED_ATTRS, NEW_ACE_DELETE_CHILD, NEW_ACE_READ_ATTRIBUTES, NEW_ACE_WRITE_ATTRIBUTES, NEW_ACE_DELETE, NEW_ACE_READ_ACL, NEW_ACE_WRITE_ACL, NEW_ACE_WRITE_OWNER, NEW_ACE_SYNCHRONIZE): New macros. * lib/set-mode-acl.c (qset_acl): On newer Solaris 10, use acl or facl instead of acl_fromtext, acl_set, facl_set. Fixes a coreutils/tests/cp/perm failure.
author Bruno Haible <bruno@clisp.org>
date Mon, 05 Sep 2011 00:44:13 +0200
parents f888e5e48e69
children 8c7936106a14
files ChangeLog lib/acl-internal.h lib/set-mode-acl.c
diffstat 3 files changed, 169 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2011-09-04  Bruno Haible  <bruno@clisp.org>
+
+	acl: Improve support of NFSv4 ACLs on Solaris 10 (newer version).
+	* lib/acl-internal.h (ACE_*, NEW_ACE_*): Define also on newer Solaris
+	10.
+	(OLD_ALLOW, OLD_DENY): New macros.
+	(NEW_ACE_ACCESS_ALLOWED_ACE_TYPE): Renamed from
+	ACE_ACCESS_ALLOWED_ACE_TYPE.
+	(NEW_ACE_ACCESS_DENIED_ACE_TYPE): Renamed from
+	ACE_ACCESS_DENIED_ACE_TYPE.
+	(OLD_ACE_OWNER, OLD_ACE_GROUP, OLD_ACE_OTHER): New macros.
+	(NEW_ACE_EXECUTE): Fix value.
+	(NEW_ACE_APPEND_DATA, NEW_ACE_READ_NAMED_ATTRS,
+	NEW_ACE_WRITE_NAMED_ATTRS, NEW_ACE_DELETE_CHILD,
+	NEW_ACE_READ_ATTRIBUTES, NEW_ACE_WRITE_ATTRIBUTES, NEW_ACE_DELETE,
+	NEW_ACE_READ_ACL, NEW_ACE_WRITE_ACL, NEW_ACE_WRITE_OWNER,
+	NEW_ACE_SYNCHRONIZE): New macros.
+	* lib/set-mode-acl.c (qset_acl): On newer Solaris 10, use acl or facl
+	instead of acl_fromtext, acl_set, facl_set.
+	Fixes a coreutils/tests/cp/perm failure.
+
 2011-09-03  Paul Eggert  <eggert@cs.ucla.edu>
 
 	openat: test for fstatat (..., 0) bug
--- a/lib/acl-internal.h
+++ b/lib/acl-internal.h
@@ -189,7 +189,9 @@
    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 */
+#  endif
+
+#  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.
@@ -199,19 +201,33 @@
 /* Definitions for when the built executable is executed on Solaris 10
    (newer version) or Solaris 11.  */
 /* For a_type.  */
-#    define ACE_ACCESS_ALLOWED_ACE_TYPE 0 /* replaces ALLOW */
-#    define ACE_ACCESS_DENIED_ACE_TYPE  1 /* replaces DENY */
+#   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 NEW_ACE_OWNER            0x1000
-#    define NEW_ACE_GROUP            0x2000
-#    define NEW_ACE_IDENTIFIER_GROUP 0x0040
-#    define ACE_EVERYONE             0x4000
+#   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_EXECUTE    0x004 /* corresponds to 'x' */
-
-#   endif
+#   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
 
--- a/lib/set-mode-acl.c
+++ b/lib/set-mode-acl.c
@@ -203,7 +203,7 @@
 
 # elif HAVE_FACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */
 
-#  if defined ACL_NO_TRIVIAL
+#  if defined ACL_NO_TRIVIAL && 0
   /* 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, ...).  */
@@ -250,6 +250,8 @@
 
 #  else /* Solaris, Cygwin, general case */
 
+  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).  */
@@ -292,7 +294,7 @@
 
             convention = 0;
             for (i = 0; i < count; i++)
-              if (entries[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_OTHER))
+              if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER))
                 {
                   convention = 1;
                   break;
@@ -308,90 +310,153 @@
 
   if (convention >= 0)
     {
-      ace_t entries[3];
+      ace_t entries[6];
+      int count;
       int ret;
 
       if (convention)
         {
           /* Running on Solaris 10.  */
-          entries[0].a_type = ALLOW;
-          entries[0].a_flags = ACE_OWNER;
+          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 = ALLOW;
-          entries[1].a_flags = ACE_GROUP;
+          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 = ALLOW;
-          entries[2].a_flags = ACE_OTHER;
+          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.  */
-          entries[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+          /* Running on Solaris 10 (newer version) or Solaris 11.
+             The details here were found through "/bin/ls -lvd somefiles".  */
+          struct stat statbuf;
+          int dir;
+
+          if ((desc != -1 ? fstat (desc, &statbuf) : stat (name, &statbuf)) >= 0)
+            dir = S_ISDIR (statbuf.st_mode);
+          else
+            dir = 0;
+
+          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 =
-            (mode & 0400 ? NEW_ACE_READ_DATA : 0)
-            | (mode & 0200 ? NEW_ACE_WRITE_DATA : 0)
-            | (mode & 0100 ? NEW_ACE_EXECUTE : 0);
-          entries[1].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
-          entries[1].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
+          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 =
-            (mode & 0040 ? NEW_ACE_READ_DATA : 0)
-            | (mode & 0020 ? NEW_ACE_WRITE_DATA : 0)
-            | (mode & 0010 ? NEW_ACE_EXECUTE : 0);
-          entries[2].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
-          entries[2].a_flags = ACE_EVERYONE;
-          entries[2].a_who = 0;
-          entries[2].a_access_mask =
-            (mode & 0004 ? NEW_ACE_READ_DATA : 0)
-            | (mode & 0002 ? NEW_ACE_WRITE_DATA : 0)
-            | (mode & 0001 ? NEW_ACE_EXECUTE : 0);
+          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 = 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 = 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,
-                    sizeof (entries) / sizeof (ace_t), entries);
+        ret = facl (desc, ACE_SETACL, count, entries);
       else
-        ret = acl (name, ACE_SETACL,
-                   sizeof (entries) / sizeof (ace_t), entries);
+        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
 
-  {
-    aclent_t entries[3];
-    int ret;
+  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;
+      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 (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)))
     {