From 7e766e7fc7aecffc5b37f4b799921de254a8450d Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 8 Jun 2008 19:08:22 +0200 Subject: [PATCH] Add support for HP-UX ACLs. --- ChangeLog | 9 +++++++ lib/acl-internal.h | 6 +++++ lib/copy-acl.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/file-has-acl.c | 59 +++++++++++++++++++++++++++++++++++++++++ lib/set-mode-acl.c | 42 +++++++++++++++++++++++++++++ 5 files changed, 194 insertions(+) diff --git a/ChangeLog b/ChangeLog index 9ff15ce1c..90eca9494 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2008-06-08 Bruno Haible + Add support for HP-UX ACLs. + * lib/acl-internal.h (acl_nontrivial): New declaration. + * lib/file-has-acl.c (acl_nontrivial): New function. + (file_has_acl): Add implementation using HP-UX 11 ACL API. + * lib/set-mode-acl.c (qset_acl): Likewise. + * lib/copy-acl.c (qcopy_acl): Likewise. + +2008-06-08 Bruno Haible + Add support for Cygwin ACLs. * lib/acl-internal.h (MODE_INSIDE_ACL): New macro for Solaris-like API. * lib/set-mode-acl.c (qset_acl) [!MODE_INSIDE_ACL]: Don't optimize away diff --git a/lib/acl-internal.h b/lib/acl-internal.h index f629eeb1f..af7396e92 100644 --- a/lib/acl-internal.h +++ b/lib/acl-internal.h @@ -179,6 +179,12 @@ extern int acl_nontrivial (int count, aclent_t *entries); extern int acl_ace_nontrivial (int count, ace_t *entries); # endif +# elif HAVE_GETACL /* HP-UX */ + +/* Return 1 if the given ACL is non-trivial. + Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ +extern int acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb); + # endif #endif diff --git a/lib/copy-acl.c b/lib/copy-acl.c index d20fa04bb..73f370c9a 100644 --- a/lib/copy-acl.c +++ b/lib/copy-acl.c @@ -392,6 +392,84 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name, # endif +#elif USE_ACL && HAVE_GETACL /* HP-UX */ + + int count; + struct acl_entry entries[NACLENTRIES]; + int ret; + + for (;;) + { + count = (source_desc != -1 + ? fgetacl (source_desc, 0, NULL) + : getacl (src_name, 0, NULL)); + + if (count < 0) + { + if (errno == ENOSYS || errno == EOPNOTSUPP) + { + count = 0; + break; + } + else + return -2; + } + + if (count == 0) + break; + + if (count > NACLENTRIES) + /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ + abort (); + + if ((source_desc != -1 + ? fgetacl (source_desc, count, entries) + : getacl (src_name, count, entries)) + == count) + break; + /* Huh? The number of ACL entries changed since the last call. + Repeat. */ + } + + if (count == 0) + return qset_acl (dst_name, dest_desc, mode); + + ret = (dest_desc != -1 + ? fsetacl (dest_desc, count, entries) + : setacl (dst_name, count, entries)); + if (ret < 0) + { + int saved_errno = errno; + + if (errno == ENOSYS || errno == EOPNOTSUPP) + { + struct stat source_statbuf; + + if ((source_desc != -1 + ? fstat (source_desc, &source_statbuf) + : stat (src_name, &source_statbuf)) == 0) + { + if (!acl_nontrivial (count, entries, &source_statbuf)) + return chmod_or_fchmod (dst_name, dest_desc, mode); + } + else + saved_errno = errno; + } + + chmod_or_fchmod (dst_name, dest_desc, mode); + errno = saved_errno; + return -1; + } + + if (mode & (S_ISUID | S_ISGID | S_ISVTX)) + { + /* We did not call chmod so far, and either the mode and the ACL are + separate or special bits are to be set which don't fit into ACLs. */ + + return chmod_or_fchmod (dst_name, dest_desc, mode); + } + return 0; + #else return qset_acl (dst_name, dest_desc, mode); diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index cbcc86d1f..50e60d515 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -174,6 +174,27 @@ acl_ace_nontrivial (int count, ace_t *entries) # endif +#elif USE_ACL && HAVE_GETACL /* HP-UX */ + +/* Return 1 if the given ACL is non-trivial. + Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ +int +acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb) +{ + int i; + + for (i = 0; i < count; i++) + { + struct acl_entry *ace = &entries[i]; + + if (!((ace->uid == sb->st_uid && ace->gid == ACL_NSGROUP) + || (ace->uid == ACL_NSUSER && ace->gid == sb->st_gid) + || (ace->uid == ACL_NSUSER && ace->gid == ACL_NSGROUP))) + return 1; + } + return 0; +} + #endif @@ -371,6 +392,44 @@ file_has_acl (char const *name, struct stat const *sb) return 0; # endif +# elif HAVE_GETACL /* HP-UX */ + + int count; + struct acl_entry entries[NACLENTRIES]; + + for (;;) + { + count = getacl (name, 0, NULL); + + if (count < 0) + return (errno == ENOSYS || errno == EOPNOTSUPP ? 0 : -1); + + if (count == 0) + return 0; + + if (count > NACLENTRIES) + /* If NACLENTRIES cannot be trusted, use dynamic memory + allocation. */ + abort (); + + /* If there are more than 3 entries, there cannot be only the + (uid,%), (%,gid), (%,%) entries. */ + if (count > 3) + return 1; + + if (getacl (name, count, entries) == count) + { + struct stat statbuf; + + if (stat (name, &statbuf) < 0) + return -1; + + return acl_nontrivial (count, entries, &statbuf); + } + /* Huh? The number of ACL entries changed since the last call. + Repeat. */ + } + # endif } #endif diff --git a/lib/set-mode-acl.c b/lib/set-mode-acl.c index b5b14ad4d..c25c5fe3d 100644 --- a/lib/set-mode-acl.c +++ b/lib/set-mode-acl.c @@ -315,6 +315,48 @@ qset_acl (char const *name, int desc, mode_t mode) # endif +# elif HAVE_GETACL /* HP-UX */ + + struct stat statbuf; + struct acl_entry entries[3]; + int ret; + + if (desc != -1) + ret = fstat (desc, &statbuf); + else + ret = stat (name, &statbuf); + if (ret < 0) + return -1; + + entries[0].uid = statbuf.st_uid; + entries[0].gid = ACL_NSGROUP; + entries[0].mode = (mode >> 6) & 7; + entries[1].uid = ACL_NSUSER; + entries[1].gid = statbuf.st_gid; + entries[1].mode = (mode >> 3) & 7; + entries[2].uid = ACL_NSUSER; + entries[2].gid = ACL_NSGROUP; + entries[2].mode = mode & 7; + + if (desc != -1) + ret = fsetacl (desc, sizeof (entries) / sizeof (struct acl_entry), entries); + else + ret = setacl (name, sizeof (entries) / sizeof (struct acl_entry), entries); + if (ret < 0) + { + if (errno == ENOSYS || errno == EOPNOTSUPP) + return chmod_or_fchmod (name, desc, mode); + return -1; + } + + if (mode & (S_ISUID | S_ISGID | S_ISVTX)) + { + /* We did not call chmod so far, so the special bits have not yet + been set. */ + return chmod_or_fchmod (name, desc, mode); + } + return 0; + # else /* Unknown flavor of ACLs */ return chmod_or_fchmod (name, desc, mode); # endif -- 2.11.0