bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

acl: new function for testing triviality of ACL


From: Bruno Haible
Subject: acl: new function for testing triviality of ACL
Date: Tue, 3 Jun 2008 01:55:43 +0200
User-agent: KMail/1.5.4

Hi Jim,

In <http://lists.gnu.org/archive/html/bug-gnulib/2008-05/msg00159.html> you
asked to unify the ACL triviality tests used in copy-acl.c and file-has-acl.c.
This patch does it, at least for the POSIX-draft like APIs. The other APIs
will need different auxiliary functions, since they don't have an 'acl_t'
type.

Note also that this function is meant to be applied to an ACL_TYPE_ACCESS
ACL, *not* to an ACL_TYPE_DEFAULT ACL (used for directories) or AC_TYPE_EXTENDED
(used on MacOS X). That motivates the function name acl_access_nontrivial.

Note also that this implementation does a full scan of the ACL. It does not
only count the entries. I find that a bit hazardous to just _assume_ that
the OS will return 4 entries. Especially when I saw that while Cygwin and
Solaris share the same API, Solaris returns 4 entries by default whereas
Cygwin returns 3 entries by default. It is easily imaginable that this
changes between different OS versions. - The full scan does not cause more
system calls; it uses abstract functions to traverse the ACL that is already
in memory.

OK to apply?


2008-06-02  Bruno Haible  <address@hidden>

        * lib/acl-internal.h (acl_access_nontrivial): New declaration.
        * lib/file-has-acl.c (acl_access_nontrivial): New function.
        (file_has_acl): Use it. Save errno afterwards.
        * lib/copy-acl.c (qcopy_acl): Use acl_access_nontrivial.

--- lib/acl-internal.h.orig     2008-06-03 01:53:52.000000000 +0200
+++ lib/acl-internal.h  2008-06-03 01:34:32.000000000 +0200
@@ -142,6 +142,12 @@
 extern int acl_entries (acl_t);
 #  endif
 
+/* 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
 
 #endif
--- lib/file-has-acl.c.orig     2008-06-03 01:53:52.000000000 +0200
+++ lib/file-has-acl.c  2008-06-03 01:53:48.000000000 +0200
@@ -23,6 +23,85 @@
 
 #include "acl-internal.h"
 
+
+#if USE_ACL && HAVE_ACL_GET_FILE
+
+/* 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)
+{
+# if MODE_INSIDE_ACL /* Linux, FreeBSD, IRIX, Tru64 */
+  /* 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 at_end;
+
+  for (at_end = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
+       !at_end;
+       at_end = 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 0;
+
+#  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 = ace->entry->acl_type;
+
+      if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
+       return 1;
+    }
+  return 0;
+
+#   endif
+#  endif
+# else /* MacOS X */
+
+  /* acl is non-trivial if it is non-empty.  */
+  return (acl_entries (acl) > 0);
+# endif
+}
+
+#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 FILE.  */
@@ -57,8 +136,12 @@
          acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
          if (acl)
            {
-             ret = (3 * MODE_INSIDE_ACL < acl_entries (acl));
+             int saved_errno;
+
+             ret = acl_access_nontrivial (acl);
+             saved_errno = errno;
              acl_free (acl);
+             errno = saved_errno;
              if (ret == 0 && S_ISDIR (sb->st_mode))
                {
                  acl = acl_get_file (name, ACL_TYPE_DEFAULT);
--- lib/copy-acl.c.orig 2008-06-03 01:53:52.000000000 +0200
+++ lib/copy-acl.c      2008-06-03 01:20:47.000000000 +0200
@@ -68,16 +68,11 @@
 
       if (ACL_NOT_WELL_SUPPORTED (errno))
         {
-         int n = acl_entries (acl);
+         int nontrivial = acl_access_nontrivial (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 (!nontrivial)
            {
              if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
                saved_errno = errno;





reply via email to

[Prev in Thread] Current Thread [Next in Thread]