changeset 10182:4a177f4b083f

Add support for HP-UX ACLs.
author Bruno Haible <bruno@clisp.org>
date Sun, 08 Jun 2008 19:08:22 +0200
parents 5282ccc922b9
children e8efce9962b0
files ChangeLog lib/acl-internal.h lib/copy-acl.c lib/file-has-acl.c lib/set-mode-acl.c
diffstat 5 files changed, 194 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+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.
--- a/lib/acl-internal.h
+++ b/lib/acl-internal.h
@@ -179,6 +179,12 @@
 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
--- a/lib/copy-acl.c
+++ b/lib/copy-acl.c
@@ -392,6 +392,84 @@
 
 # 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);
--- a/lib/file-has-acl.c
+++ b/lib/file-has-acl.c
@@ -174,6 +174,27 @@
 
 # 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 @@
       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
--- a/lib/set-mode-acl.c
+++ b/lib/set-mode-acl.c
@@ -315,6 +315,48 @@
 
 #  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