[Top][All Lists]
[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;
- acl: new function for testing triviality of ACL,
Bruno Haible <=