summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2008-06-08 19:08:22 +0200
committerBruno Haible <bruno@clisp.org>2008-06-08 19:08:22 +0200
commit7e766e7fc7aecffc5b37f4b799921de254a8450d (patch)
tree28fa8a9d27fa27823f021577120f91339d7e2da9
parentc3dcd03b1c12d7a7e80e573dd09168feb469b1e2 (diff)
downloadgnulib-7e766e7fc7aecffc5b37f4b799921de254a8450d.tar.gz
Add support for HP-UX ACLs.
-rw-r--r--ChangeLog9
-rw-r--r--lib/acl-internal.h6
-rw-r--r--lib/copy-acl.c78
-rw-r--r--lib/file-has-acl.c59
-rw-r--r--lib/set-mode-acl.c42
5 files changed, 194 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 9ff15ce1c2..90eca94949 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
2008-06-08 Bruno Haible <bruno@clisp.org>
+ 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 <bruno@clisp.org>
+
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 f629eeb1f1..af7396e92a 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 d20fa04bb1..73f370c9aa 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 cbcc86d1f4..50e60d5150 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 b5b14ad4d0..c25c5fe3d8 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