Mercurial > hg > octave-nkf > gnulib-hg
changeset 10158:73042342e7f6
New function for testing triviality of ACL with POSIX-draft like API.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Wed, 04 Jun 2008 22:48:48 +0200 |
parents | 0c183af9efd5 |
children | 873cd96bbc65 |
files | ChangeLog lib/acl-internal.h lib/copy-acl.c lib/file-has-acl.c |
diffstat | 4 files changed, 108 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-06-04 Bruno Haible <bruno@clisp.org> + + * 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. + 2008-06-03 Bruno Haible <bruno@clisp.org> * lib/file-has-acl.c (file_has_acl): Put Solaris 10 code after POSIX-
--- a/lib/acl-internal.h +++ b/lib/acl-internal.h @@ -145,6 +145,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
--- a/lib/copy-acl.c +++ b/lib/copy-acl.c @@ -68,15 +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. - 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;
--- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -23,6 +23,93 @@ #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; + acl_perm_t perm; + + tag = ace->entry->acl_type; + if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER)) + return 1; + + perm = ace->entry->acl_perm; + /* On Tru64, perm can also contain non-standard bits such as + PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ... */ + if ((perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)) != 0) + 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. */ @@ -46,8 +133,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);