NEWS.stable: log cherry-pick [8b18afa]->[c948e19] sys_select: Avoid a syntax error...
[gnulib.git] / lib / file-has-acl.c
index a815e4c..2ee6ba2 100644 (file)
@@ -234,6 +234,33 @@ acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb)
   return 0;
 }
 
+# if HAVE_ACLV_H /* HP-UX >= 11.11 */
+
+/* Return 1 if the given ACL is non-trivial.
+   Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
+int
+aclv_nontrivial (int count, struct acl *entries)
+{
+  int i;
+
+  for (i = 0; i < count; i++)
+    {
+      struct acl *ace = &entries[i];
+
+      /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
+         If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
+         We don't need to check ace->a_id in these cases.  */
+      if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */
+            || ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */
+            || ace->a_type == CLASS_OBJ
+            || ace->a_type == OTHER_OBJ))
+        return 1;
+    }
+  return 0;
+}
+
+# endif
+
 #elif USE_ACL && (HAVE_ACLX_GET || HAVE_STATACL) /* AIX */
 
 /* Return 1 if the given ACL is non-trivial.
@@ -339,12 +366,20 @@ file_has_acl (char const *name, struct stat const *sb)
       /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
       int ret;
 
-      if (HAVE_ACL_EXTENDED_FILE) /* Linux */
+      if (HAVE_ACL_EXTENDED_FILE || HAVE_ACL_EXTENDED_FILE_NOFOLLOW) /* Linux */
         {
+#  if HAVE_ACL_EXTENDED_FILE_NOFOLLOW
+          /* acl_extended_file_nofollow() uses lgetxattr() in order to prevent
+             unnecessary mounts, but it returns the same result as we already
+             know that NAME is not a symbolic link at this point (modulo the
+             TOCTTOU race condition).  */
+          ret = acl_extended_file_nofollow (name);
+#  else
           /* On Linux, acl_extended_file is an optimized function: It only
              makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
              ACL_TYPE_DEFAULT.  */
           ret = acl_extended_file (name);
+#  endif
         }
       else /* FreeBSD, MacOS X, IRIX, Tru64 */
         {
@@ -519,15 +554,23 @@ file_has_acl (char const *name, struct stat const *sb)
 
 # elif HAVE_GETACL /* HP-UX */
 
-      int count;
-      struct acl_entry entries[NACLENTRIES];
-
       for (;;)
         {
+          int count;
+          struct acl_entry entries[NACLENTRIES];
+
           count = getacl (name, 0, NULL);
 
           if (count < 0)
-            return (errno == ENOSYS || errno == EOPNOTSUPP ? 0 : -1);
+            {
+              /* ENOSYS is seen on newer HP-UX versions.
+                 EOPNOTSUPP is typically seen on NFS mounts.
+                 ENOTSUP was seen on Quantum StorNext file systems (cvfs).  */
+              if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
+                break;
+              else
+                return -1;
+            }
 
           if (count == 0)
             return 0;
@@ -555,6 +598,46 @@ file_has_acl (char const *name, struct stat const *sb)
              Repeat.  */
         }
 
+#  if HAVE_ACLV_H /* HP-UX >= 11.11 */
+
+      for (;;)
+        {
+          int count;
+          struct acl entries[NACLVENTRIES];
+
+          count = acl ((char *) name, ACL_CNT, NACLVENTRIES, entries);
+
+          if (count < 0)
+            {
+              /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
+                 EINVAL is seen on NFS in HP-UX 11.31.  */
+              if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
+                break;
+              else
+                return -1;
+            }
+
+          if (count == 0)
+            return 0;
+
+          if (count > NACLVENTRIES)
+            /* If NACLVENTRIES cannot be trusted, use dynamic memory
+               allocation.  */
+            abort ();
+
+          /* If there are more than 4 entries, there cannot be only the
+             four base ACL entries.  */
+          if (count > 4)
+            return 1;
+
+          if (acl ((char *) name, ACL_GET, count, entries) == count)
+            return aclv_nontrivial (count, entries);
+          /* Huh? The number of ACL entries changed since the last call.
+             Repeat.  */
+        }
+
+#  endif
+
 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
 
       acl_type_t type;