Author: trasz
Date: Mon Sep 20 17:10:06 2010
New Revision: 212906
URL: http://svn.freebsd.org/changeset/base/212906

Log:
  First step at adopting FreeBSD to support PSARC/2010/029.  This makes
  acl_is_trivial_np(3) properly recognize the new trivial ACLs.  From
  the user point of view, that means "ls -l" no longer shows plus signs
  for all the files when running ZFS v28.

Modified:
  head/lib/libc/posix1e/acl_strip.c
  head/sys/kern/subr_acl_nfs4.c
  head/sys/sys/acl.h

Modified: head/lib/libc/posix1e/acl_strip.c
==============================================================================
--- head/lib/libc/posix1e/acl_strip.c   Mon Sep 20 17:03:10 2010        
(r212905)
+++ head/lib/libc/posix1e/acl_strip.c   Mon Sep 20 17:10:06 2010        
(r212906)
@@ -31,19 +31,21 @@ __FBSDID("$FreeBSD$");
 #include <stdio.h>
 #include <assert.h>
 #include <sys/acl.h>
+#include <sys/stat.h>
 
 #include "acl_support.h"
 
 /*
- * These two routines from sys/kern/subr_acl_nfs4.c are used by both kernel
+ * These three routines from sys/kern/subr_acl_nfs4.c are used by both kernel
  * and libc.
  */
+void   acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode);
 void   acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode,
            int file_owner_id);
 void   acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp);
 
 static acl_t
-_nfs4_acl_strip_np(const acl_t aclp, int recalculate_mask)
+_nfs4_acl_strip_np(const acl_t aclp, int canonical_six)
 {
        acl_t newacl;
        mode_t mode = 0;
@@ -57,7 +59,10 @@ _nfs4_acl_strip_np(const acl_t aclp, int
        _acl_brand_as(newacl, ACL_BRAND_NFS4);
 
        acl_nfs4_sync_mode_from_acl(&mode, &(aclp->ats_acl));
-       acl_nfs4_sync_acl_from_mode(&(newacl->ats_acl), mode, -1);
+       if (canonical_six)
+               acl_nfs4_sync_acl_from_mode(&(newacl->ats_acl), mode, -1);
+       else
+               acl_nfs4_trivial_from_mode(&(newacl->ats_acl), mode);
 
        return (newacl);
 }
@@ -136,7 +141,7 @@ acl_strip_np(const acl_t aclp, int recal
 {
        switch (_acl_brand(aclp)) {
        case ACL_BRAND_NFS4:
-               return (_nfs4_acl_strip_np(aclp, recalculate_mask));
+               return (_nfs4_acl_strip_np(aclp, 1));
 
        case ACL_BRAND_POSIX:
                return (_posix1e_acl_strip_np(aclp, recalculate_mask));
@@ -185,10 +190,25 @@ acl_is_trivial_np(const acl_t aclp, int 
                }
                        
                /*
-                * Calculate trivial ACL - using acl_strip_np - and compare
+                * Calculate trivial ACL - using acl_strip_np(3) - and compare
                 * with the original.
                 */
-               tmpacl = acl_strip_np(aclp, 0);
+               tmpacl = _nfs4_acl_strip_np(aclp, 0);
+               if (tmpacl == NULL)
+                       return (-1);
+
+               differs = _acl_differs(aclp, tmpacl);
+               acl_free(tmpacl);
+
+               if (differs == 0) {
+                       *trivialp = 1;
+                       return (0);
+               }
+
+               /*
+                * Try again with an old-style, "canonical six" trivial ACL.
+                */
+               tmpacl = _nfs4_acl_strip_np(aclp, 1);
                if (tmpacl == NULL)
                        return (-1);
 

Modified: head/sys/kern/subr_acl_nfs4.c
==============================================================================
--- head/sys/kern/subr_acl_nfs4.c       Mon Sep 20 17:03:10 2010        
(r212905)
+++ head/sys/kern/subr_acl_nfs4.c       Mon Sep 20 17:10:06 2010        
(r212906)
@@ -349,6 +349,83 @@ _acl_duplicate_entry(struct acl *aclp, i
        return (&(aclp->acl_entry[entry_index + 1]));
 }
 
+/*
+ * Calculate trivial ACL in a manner compatible with PSARC/2010/029.
+ * Note that this results in an ACL different from (but semantically
+ * equal to) the "canonical six" trivial ACL computed using algorithm
+ * described in draft-ietf-nfsv4-minorversion1-03.txt, 3.16.6.2.
+ */
+void
+acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode)
+{
+       acl_perm_t user_allow_first = 0, user_deny = 0, group_deny = 0;
+       acl_perm_t user_allow, group_allow, everyone_allow;
+
+       KASSERT(aclp->acl_cnt == 0, ("aclp->acl_cnt == 0"));
+
+       user_allow = group_allow = everyone_allow = ACL_READ_ACL |
+           ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | ACL_SYNCHRONIZE;
+       user_allow |= ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
+           ACL_WRITE_NAMED_ATTRS;
+
+       if (mode & S_IRUSR)
+               user_allow |= ACL_READ_DATA;
+       if (mode & S_IWUSR)
+               user_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
+       if (mode & S_IXUSR)
+               user_allow |= ACL_EXECUTE;
+
+       if (mode & S_IRGRP)
+               group_allow |= ACL_READ_DATA;
+       if (mode & S_IWGRP)
+               group_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
+       if (mode & S_IXGRP)
+               group_allow |= ACL_EXECUTE;
+
+       if (mode & S_IROTH)
+               everyone_allow |= ACL_READ_DATA;
+       if (mode & S_IWOTH)
+               everyone_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
+       if (mode & S_IXOTH)
+               everyone_allow |= ACL_EXECUTE;
+
+       user_deny = ((group_allow | everyone_allow) & ~user_allow);
+       group_deny = everyone_allow & ~group_allow;
+       user_allow_first = group_deny & ~user_deny;
+
+#if 1
+       /*
+        * This is a workaround for what looks like a bug in ZFS - trivial
+        * ACL for mode 0077 should look like this:
+        *
+        *    owner@:rwxp----------:------:deny
+        *    owner@:------aARWcCos:------:allow
+        *    group@:rwxp--a-R-c--s:------:allow
+        * everyone@:rwxp--a-R-c--s:------:allow
+        *
+        * Instead, ZFS makes it like this:
+        *
+        *    owner@:rwx-----------:------:deny
+        *    owner@:------aARWcCos:------:allow
+        *    group@:rwxp--a-R-c--s:------:allow
+        * everyone@:rwxp--a-R-c--s:------:allow
+        */
+       user_allow_first &= ~ACL_APPEND_DATA;
+       user_deny &= ~ACL_APPEND_DATA;
+       group_deny &= ~ACL_APPEND_DATA;
+#endif
+
+       if (user_allow_first != 0)
+               _acl_append(aclp, ACL_USER_OBJ, user_allow_first, 
ACL_ENTRY_TYPE_ALLOW);
+       if (user_deny != 0)
+               _acl_append(aclp, ACL_USER_OBJ, user_deny, ACL_ENTRY_TYPE_DENY);
+       if (group_deny != 0)
+               _acl_append(aclp, ACL_GROUP_OBJ, group_deny, 
ACL_ENTRY_TYPE_DENY);
+       _acl_append(aclp, ACL_USER_OBJ, user_allow, ACL_ENTRY_TYPE_ALLOW);
+       _acl_append(aclp, ACL_GROUP_OBJ, group_allow, ACL_ENTRY_TYPE_ALLOW);
+       _acl_append(aclp, ACL_EVERYONE, everyone_allow, ACL_ENTRY_TYPE_ALLOW);
+}
+
 void
 acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, int file_owner_id)
 {

Modified: head/sys/sys/acl.h
==============================================================================
--- head/sys/sys/acl.h  Mon Sep 20 17:03:10 2010        (r212905)
+++ head/sys/sys/acl.h  Mon Sep 20 17:10:06 2010        (r212906)
@@ -285,6 +285,8 @@ mode_t                      acl_posix1e_newfilemode(mode_t 
 struct acl             *acl_alloc(int flags);
 void                   acl_free(struct acl *aclp);
 
+void                   acl_nfs4_trivial_from_mode(struct acl *aclp,
+                           mode_t mode);
 void                   acl_nfs4_sync_acl_from_mode(struct acl *aclp,
                            mode_t mode, int file_owner_id);
 void                   acl_nfs4_sync_mode_from_acl(mode_t *mode,
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to