* lib/dirent.in.h (_GL_DT_NOTDIR): New macro.
* lib/acl.h (ACL_SYMLINK_FOLLOW): Increase value.
* lib/file-has-acl.c (file_has_aclinfo): Don't call
acl_get_file (name, ACL_TYPE_DEFAULT) if we know that name does not
denote a directory.
(file_has_acl): Extract from *SB the information that NAME is not a
directory.
+2024-10-07 Bruno Haible <bruno@clisp.org>
+
+ file-has-acl: Fix performance regression on FreeBSD, Cygwin.
+ * lib/dirent.in.h (_GL_DT_NOTDIR): New macro.
+ * lib/acl.h (ACL_SYMLINK_FOLLOW): Increase value.
+ * lib/file-has-acl.c (file_has_aclinfo): Don't call
+ acl_get_file (name, ACL_TYPE_DEFAULT) if we know that name does not
+ denote a directory.
+ (file_has_acl): Extract from *SB the information that NAME is not a
+ directory.
+
2024-10-07 Bruno Haible <bruno@clisp.org>
file-has-acl: Fix comments.
extern "C" {
#endif
-/* Follow symlinks when getting an ACL. This is greater than any
- unsigned char so that it can be ORed with any <dirent.h> DT_* value. */
-enum { ACL_SYMLINK_FOLLOW = 1 + (unsigned char) -1 };
+/* Follow symlinks when getting an ACL. This is a bitmask that is guaranteed
+ not to collide with any <dirent.h> DT_* or _GL_DT_* value. */
+enum { ACL_SYMLINK_FOLLOW = 0x10000 };
/* Information about an ACL. */
struct aclinfo
but not (yet) DT_MQ, DT_SEM, DT_SHM, DT_TMO.
These macros can be useful even on platforms that do not support
d_type or the corresponding file types.
+ The values of these macros are all in the 'unsigned char' range.
Default to the Linux values which are also popular elsewhere,
and check that all macros have distinct values. */
#ifndef DT_UNKNOWN
&& DT_LNK != DT_SOCK && DT_LNK != DT_WHT
&& DT_SOCK != DT_WHT);
+/* Other optional information about a directory entry. */
+#define _GL_DT_NOTDIR 0x100 /* Not a directory */
+
/* Conversion between S_IF* and DT_* file types. */
#if ! (defined IFTODT && defined DTTOIF)
# include <sys/stat.h>
# define _GL_DIRENT_S_IFWHT (DT_WHT << 12) /* just a guess */
# endif
#endif
+/* Conversion from a 'stat' mode to a DT_* value. */
#ifndef IFTODT
# define IFTODT(mode) \
(S_ISREG (mode) ? DT_REG : S_ISDIR (mode) ? DT_DIR \
: S_ISSOCK (mode) ? DT_SOCK \
: _GL_DIRENT_S_ISWHT (mode) ? DT_WHT : DT_UNKNOWN)
#endif
+/* Conversion from a DT_* value to a 'stat' mode. */
#ifndef DTTOIF
# define DTTOIF(dirtype) \
((dirtype) == DT_REG ? S_IFREG : (dirtype) == DT_DIR ? S_IFDIR \
if ACLs are not supported as errno is set in that case also.
Set *AI to ACL info regardless of return value.
FLAGS should be a <dirent.h> d_type value, optionally ORed with
- ACL_SYMLINK_FOLLOW; if the d_type value is not known,
- use DT_UNKNOWN though this may be less efficient.
+ - _GL_DT_NOTDIR if it is known that NAME is not a directory,
+ - ACL_SYMLINK_FOLLOW to follow the link if NAME is a symbolic link.
+ If the d_type value is not known, use DT_UNKNOWN though this may be less
+ efficient.
If FLAGS & ACL_SYMLINK_FOLLOW, follow symlinks when retrieving ACL info;
otherwise do not follow them if possible. */
int
either both succeed or both fail; it depends on the
file system. Therefore there is no point in making the second
call if the first one already failed. */
- if (ret == 0 && (d_type == DT_DIR || d_type == DT_UNKNOWN))
+ if (ret == 0
+ && (d_type == DT_DIR
+ || (d_type == DT_UNKNOWN && !(flags & _GL_DT_NOTDIR))))
{
acl = acl_get_file (name, ACL_TYPE_DEFAULT);
if (acl)
int
file_has_acl (char const *name, struct stat const *sb)
{
+ int flags = IFTODT (sb->st_mode);
+ if (!S_ISDIR (sb->st_mode))
+ flags |= _GL_DT_NOTDIR;
struct aclinfo ai;
- int r = file_has_aclinfo (name, &ai, IFTODT (sb->st_mode));
+ int r = file_has_aclinfo (name, &ai, flags);
aclinfo_free (&ai);
return r;
}