It is relatively easy to support O_DIRECTORY on platforms that
lack it, so let’s do that instead of having to work around bugs
like <https://bugs.gnu.org/78509#95>.
* lib/fcntl.in.h (O_DIRECTORY): Default to 0x20000000 not 0,
since Gnulib now supports it.
* lib/open.c, lib/openat.c (OPEN_TRAILING_SLASH_BUG):
Default to false, so that this can be used outside #if.
(open, openat): Add support for O_DIRECTORY on platforms that lack it.
If fstat fails, fail instead of assuming the file is a directory,
since failure can occur due to EOVERFLOW, etc.
Rearrange code to minimize differences between open.c and openat.c.
* m4/fcntl-o.m4 (gl_FCNTL_O_FLAGS): Also test O_DIRECTORY,
and define HAVE_WORKING_O_DIRECTORY if needed.
Prefer AS_CASE for Emacs’s benefit.
* m4/open.m4 (gl_FUNC_OPEN):
* m4/openat.m4 (gl_FUNC_OPENAT):
Require gl_FCNTL_O_FLAGS and replace the function
if O_DIRECTORY does not work.
* tests/test-open.h: Test O_DIRECTORY.
---
 ChangeLog                       | 23 ++++++++++
 doc/posix-functions/open.texi   |  4 ++
 doc/posix-functions/openat.texi |  4 ++
 doc/posix-headers/fcntl.texi    |  7 ++-
 lib/fcntl.in.h                  |  2 +-
 lib/open.c                      | 60 +++++++++++++-------------
 lib/openat.c                    | 44 ++++++++++---------
 m4/fcntl-o.m4                   | 75 ++++++++++++++++++++++-----------
 m4/open.m4                      |  5 ++-
 m4/openat.m4                    | 21 +++------
 tests/test-open.h               |  5 +++
 11 files changed, 159 insertions(+), 91 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9351692a28..e67f901f54 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2025-05-26  Paul Eggert  <egg...@cs.ucla.edu>
+
+       fcntl-h: support O_DIRECTORY
+       It is relatively easy to support O_DIRECTORY on platforms that
+       lack it, so let’s do that instead of having to work around bugs
+       like <https://bugs.gnu.org/78509#95>.
+       * lib/fcntl.in.h (O_DIRECTORY): Default to 0x20000000 not 0,
+       since Gnulib now supports it.
+       * lib/open.c, lib/openat.c (OPEN_TRAILING_SLASH_BUG):
+       Default to false, so that this can be used outside #if.
+       (open, openat): Add support for O_DIRECTORY on platforms that lack it.
+       If fstat fails, fail instead of assuming the file is a directory,
+       since failure can occur due to EOVERFLOW, etc.
+       Rearrange code to minimize differences between open.c and openat.c.
+       * m4/fcntl-o.m4 (gl_FCNTL_O_FLAGS): Also test O_DIRECTORY,
+       and define HAVE_WORKING_O_DIRECTORY if needed.
+       Prefer AS_CASE for Emacs’s benefit.
+       * m4/open.m4 (gl_FUNC_OPEN):
+       * m4/openat.m4 (gl_FUNC_OPENAT):
+       Require gl_FCNTL_O_FLAGS and replace the function
+       if O_DIRECTORY does not work.
+       * tests/test-open.h: Test O_DIRECTORY.
+
 2025-05-26  Collin Funk  <collin.fu...@gmail.com>
 
        crypto/gc: Simplify the previous change.
diff --git a/doc/posix-functions/open.texi b/doc/posix-functions/open.texi
index a7e83e4f49..1f10f30ca9 100644
--- a/doc/posix-functions/open.texi
+++ b/doc/posix-functions/open.texi
@@ -15,6 +15,10 @@ Some platforms do not support @code{O_CLOEXEC}:
 @c See posix-headers/fcntl.texi for the list.
 Mac OS X 10.6, FreeBSD 8.4, NetBSD 5.1, OpenBSD 4.9, Minix 3.1.8, AIX 7.1, 
HP-UX 11, Solaris 10, Cygwin 1.7.x, mingw, MSVC 14.
 @item
+Some platforms do not support @code{O_DIRECTORY}:
+mingw, MSVC 14, glibc 2.0, OS X 10.9, FreeBSD 7.4, NetBSD 4.0.1, OpenBSD 4.9,
+AIX 7.1, HP-UX 11, Solaris 10.
+@item
 On platforms where @code{off_t} is a 32-bit type, @code{open} may not work
 correctly with files 2 GiB and larger.  @xref{Large File Support}.
 @item
diff --git a/doc/posix-functions/openat.texi b/doc/posix-functions/openat.texi
index c5ac2ca784..5c114dfe6d 100644
--- a/doc/posix-functions/openat.texi
+++ b/doc/posix-functions/openat.texi
@@ -18,6 +18,10 @@ But the replacement function is not safe to be used in 
libraries and is not mult
 Some platforms do not support @code{O_CLOEXEC}:
 AIX 7.1, Solaris 10.
 @item
+Some platforms do not support @code{O_DIRECTORY}:
+mingw, MSVC 14, glibc 2.0, OS X 10.9, FreeBSD 7.4, NetBSD 4.0.1, OpenBSD 4.9,
+AIX 7.1, HP-UX 11, Solaris 10.
+@item
 On platforms where @code{off_t} is a 32-bit type, @code{open} may not work
 correctly with files 2 GiB and larger.  @xref{Large File Support}.
 @item
diff --git a/doc/posix-headers/fcntl.texi b/doc/posix-headers/fcntl.texi
index 211ed49a0c..9adaecc3ae 100644
--- a/doc/posix-headers/fcntl.texi
+++ b/doc/posix-headers/fcntl.texi
@@ -25,7 +25,7 @@ macOS 14, FreeBSD 10.4, NetBSD 10.0, OpenBSD 7.5, MSVC 14, 
Cygwin, Haiku, Minix
 Mac OS X 10.6, FreeBSD 8.4, NetBSD 5.1, OpenBSD 4.9, Minix 3.1.8, AIX 7.1, 
HP-UX 11.31, Solaris 10, Cygwin 1.7.1, mingw, MSVC 14.
 
 @item
-@samp{O_DIRECTORY}, @samp{O_DSYNC}, @samp{O_NOCTTY},
+@samp{O_DSYNC}, @samp{O_NOCTTY},
 @samp{O_NOFOLLOW}, @samp{O_RSYNC}, @samp{O_SYNC},
 and @samp{O_TTY_INIT} are not defined on some platforms.
 When not otherwise defined, Gnulib defines these macros to 0,
@@ -91,6 +91,11 @@ on some platforms but not on others.
 When not otherwise defined, Gnulib defines these macros to 0,
 which is generally safe.
 
+@item
+@samp{O_DIRECTORY} is not defined on some platforms:
+mingw, MSVC 14, glibc 2.0, OS X 10.9, FreeBSD 7.4, NetBSD 4.0.1, OpenBSD 4.9,
+AIX 7.1, HP-UX 11, Solaris 10.
+
 @item
 @samp{FD_CLOEXEC}, @samp{F_DUPFD}, and @samp{F_GETFD} are not defined
 on some platforms:
diff --git a/lib/fcntl.in.h b/lib/fcntl.in.h
index 0e4c04ea9b..c5068ed48a 100644
--- a/lib/fcntl.in.h
+++ b/lib/fcntl.in.h
@@ -315,7 +315,7 @@ _GL_WARN_ON_USE (openat, "openat is not portable - "
 #endif
 
 #ifndef O_DIRECTORY
-# define O_DIRECTORY 0
+# define O_DIRECTORY 0x20000000 /* Try to not collide with system O_* flags.  
*/
 #endif
 
 #ifndef O_DSYNC
diff --git a/lib/open.c b/lib/open.c
index 7415b48f81..0d30df961a 100644
--- a/lib/open.c
+++ b/lib/open.c
@@ -55,24 +55,19 @@ orig_open (const char *filename, int flags, mode_t mode)
 #include <sys/stat.h>
 #include <unistd.h>
 
+#ifndef OPEN_TRAILING_SLASH_BUG
+# define OPEN_TRAILING_SLASH_BUG false
+#endif
+
 #ifndef REPLACE_OPEN_DIRECTORY
-# define REPLACE_OPEN_DIRECTORY 0
+# define REPLACE_OPEN_DIRECTORY false
 #endif
 
 int
 open (const char *filename, int flags, ...)
 {
-  /* 0 = unknown, 1 = yes, -1 = no.  */
-#if GNULIB_defined_O_CLOEXEC
-  int have_cloexec = -1;
-#else
-  static int have_cloexec;
-#endif
-
-  mode_t mode;
-  int fd;
+  mode_t mode = 0;
 
-  mode = 0;
   if (flags & O_CREAT)
     {
       va_list arg;
@@ -99,7 +94,6 @@ open (const char *filename, int flags, ...)
     filename = "NUL";
 #endif
 
-#if OPEN_TRAILING_SLASH_BUG
   /* Fail if one of O_CREAT, O_WRONLY, O_RDWR is specified and the filename
      ends in a slash, as POSIX says such a filename must name a directory
      
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>:
@@ -118,9 +112,10 @@ open (const char *filename, int flags, ...)
          directories,
        - if O_WRONLY or O_RDWR is specified, open() must fail because the
          file does not contain a '.' directory.  */
-  if ((flags & O_CREAT)
-      || (flags & O_ACCMODE) == O_RDWR
-      || (flags & O_ACCMODE) == O_WRONLY)
+  if (OPEN_TRAILING_SLASH_BUG
+      && (flags & O_CREAT
+          || (flags & O_ACCMODE) == O_RDWR
+          || (flags & O_ACCMODE) == O_WRONLY))
     {
       size_t len = strlen (filename);
       if (len > 0 && filename[len - 1] == '/')
@@ -129,10 +124,16 @@ open (const char *filename, int flags, ...)
           return -1;
         }
     }
+
+  /* 0 = unknown, 1 = yes, -1 = no.  */
+#if GNULIB_defined_O_CLOEXEC
+  int have_cloexec = -1;
+#else
+  static int have_cloexec;
 #endif
 
-  fd = orig_open (filename,
-                  flags & ~(have_cloexec < 0 ? O_CLOEXEC : 0), mode);
+  int fd = orig_open (filename,
+                      flags & ~(have_cloexec < 0 ? O_CLOEXEC : 0), mode);
 
   if (flags & O_CLOEXEC)
     {
@@ -175,10 +176,9 @@ open (const char *filename, int flags, ...)
     }
 #endif
 
-#if OPEN_TRAILING_SLASH_BUG
-  /* If the filename ends in a slash and fd does not refer to a directory,
-     then fail.
-     Rationale: POSIX says such a filename must name a directory
+  /* If the filename ends in a slash or O_DIRECTORY is given,
+     then fail if fd does not refer to a directory.
+     Rationale: A filename ending in slash cannot name a non-directory
      
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>:
        "A pathname that contains at least one non-<slash> character and that
         ends with one or more trailing <slash> characters shall not be resolved
@@ -186,23 +186,25 @@ open (const char *filename, int flags, ...)
         <slash> characters names an existing directory"
      If the named file without the slash is not a directory, open() must fail
      with ENOTDIR.  */
-  if (fd >= 0)
+  if (((!HAVE_WORKING_O_DIRECTORY && flags & O_DIRECTORY)
+       || OPEN_TRAILING_SLASH_BUG)
+      && 0 <= fd)
     {
-      /* We know len is positive, since open did not fail with ENOENT.  */
-      size_t len = strlen (filename);
-      if (filename[len - 1] == '/')
+      /* FILENAME must be nonempty, as open did not fail with ENOENT.  */
+      if ((!HAVE_WORKING_O_DIRECTORY && flags & O_DIRECTORY)
+          || filename[strlen (filename) - 1] == '/')
         {
           struct stat statbuf;
-
-          if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
+          int r = fstat (fd, &statbuf);
+          if (r < 0 || !S_ISDIR (statbuf.st_mode))
             {
+              int err = r < 0 ? errno : ENOTDIR;
               close (fd);
-              errno = ENOTDIR;
+              errno = err;
               return -1;
             }
         }
     }
-#endif
 
 #if REPLACE_FCHDIR
   if (!REPLACE_OPEN_DIRECTORY && 0 <= fd)
diff --git a/lib/openat.c b/lib/openat.c
index f6dce43ba7..66b53264a2 100644
--- a/lib/openat.c
+++ b/lib/openat.c
@@ -54,6 +54,10 @@ orig_openat (int fd, char const *filename, int flags, mode_t 
mode)
 #include <sys/stat.h>
 #include <errno.h>
 
+#ifndef OPEN_TRAILING_SLASH_BUG
+# define OPEN_TRAILING_SLASH_BUG false
+#endif
+
 #if HAVE_OPENAT
 
 /* Like openat, but support O_CLOEXEC and work around Solaris 9 bugs
@@ -75,7 +79,6 @@ rpl_openat (int dfd, char const *filename, int flags, ...)
       va_end (arg);
     }
 
-# if OPEN_TRAILING_SLASH_BUG
   /* Fail if one of O_CREAT, O_WRONLY, O_RDWR is specified and the filename
      ends in a slash, as POSIX says such a filename must name a directory
      
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>:
@@ -94,9 +97,10 @@ rpl_openat (int dfd, char const *filename, int flags, ...)
          directories,
        - if O_WRONLY or O_RDWR is specified, open() must fail because the
          file does not contain a '.' directory.  */
-  if ((flags & O_CREAT)
-      || (flags & O_ACCMODE) == O_RDWR
-      || (flags & O_ACCMODE) == O_WRONLY)
+  if (OPEN_TRAILING_SLASH_BUG
+      && (flags & O_CREAT
+          || (flags & O_ACCMODE) == O_RDWR
+          || (flags & O_ACCMODE) == O_WRONLY))
     {
       size_t len = strlen (filename);
       if (len > 0 && filename[len - 1] == '/')
@@ -105,14 +109,13 @@ rpl_openat (int dfd, char const *filename, int flags, ...)
           return -1;
         }
     }
-# endif
 
   /* 0 = unknown, 1 = yes, -1 = no.  */
-#if GNULIB_defined_O_CLOEXEC
+# if GNULIB_defined_O_CLOEXEC
   int have_cloexec = -1;
-#else
+# else
   static int have_cloexec;
-#endif
+# endif
 
   int fd = orig_openat (dfd, filename,
                         flags & ~(have_cloexec < 0 ? O_CLOEXEC : 0), mode);
@@ -134,10 +137,9 @@ rpl_openat (int dfd, char const *filename, int flags, ...)
     }
 
 
-# if OPEN_TRAILING_SLASH_BUG
-  /* If the filename ends in a slash and fd does not refer to a directory,
-     then fail.
-     Rationale: POSIX says such a filename must name a directory
+  /* If the filename ends in a slash or O_DIRECTORY is given,
+     then fail if fd does not refer to a directory.
+     Rationale: A filename ending in slash cannot name a non-directory
      
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>:
        "A pathname that contains at least one non-<slash> character and that
         ends with one or more trailing <slash> characters shall not be resolved
@@ -145,23 +147,25 @@ rpl_openat (int dfd, char const *filename, int flags, ...)
         <slash> characters names an existing directory"
      If the named file without the slash is not a directory, open() must fail
      with ENOTDIR.  */
-  if (fd >= 0)
+  if (((!HAVE_WORKING_O_DIRECTORY && flags & O_DIRECTORY)
+       || OPEN_TRAILING_SLASH_BUG)
+      && 0 <= fd)
     {
-      /* We know len is positive, since open did not fail with ENOENT.  */
-      size_t len = strlen (filename);
-      if (filename[len - 1] == '/')
+      /* FILENAME must be nonempty, as open did not fail with ENOENT.  */
+      if ((!HAVE_WORKING_O_DIRECTORY && flags & O_DIRECTORY)
+          || filename[strlen (filename) - 1] == '/')
         {
           struct stat statbuf;
-
-          if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
+          int r = fstat (fd, &statbuf);
+          if (r < 0 || !S_ISDIR (statbuf.st_mode))
             {
+              int err = r < 0 ? errno : ENOTDIR;
               close (fd);
-              errno = ENOTDIR;
+              errno = err;
               return -1;
             }
         }
     }
-# endif
 
   return fd;
 }
diff --git a/m4/fcntl-o.m4 b/m4/fcntl-o.m4
index 7147679654..2f0faebdd1 100644
--- a/m4/fcntl-o.m4
+++ b/m4/fcntl-o.m4
@@ -1,5 +1,5 @@
 # fcntl-o.m4
-# serial 8
+# serial 9
 dnl Copyright (C) 2006, 2009-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -10,7 +10,8 @@ dnl Written by Paul Eggert.
 
 AC_PREREQ([2.60])
 
-# Test whether the flags O_NOATIME and O_NOFOLLOW actually work.
+# Test whether the flags O_DIRECTORY, O_NOATIME and O_NOFOLLOW actually work.
+# Define HAVE_WORKING_O_DIRECTORY to 1 if O_DIRECTORY works, or to 0 otherwise.
 # Define HAVE_WORKING_O_NOATIME to 1 if O_NOATIME works, or to 0 otherwise.
 # Define HAVE_WORKING_O_NOFOLLOW to 1 if O_NOFOLLOW works, or to 0 otherwise.
 AC_DEFUN([gl_FCNTL_O_FLAGS],
@@ -33,14 +34,21 @@ AC_DEFUN([gl_FCNTL_O_FLAGS],
            # include <stdlib.h>
            # defined sleep(n) _sleep ((n) * 1000)
            #endif
+           #include <errno.h>
            #include <fcntl.h>
            ]GL_MDA_DEFINES[
+           #ifndef O_DIRECTORY
+            #define O_DIRECTORY 0
+           #endif
            #ifndef O_NOATIME
             #define O_NOATIME 0
            #endif
            #ifndef O_NOFOLLOW
             #define O_NOFOLLOW 0
            #endif
+           #ifndef O_SEARCH
+            #define O_SEARCH O_RDONLY
+           #endif
            static int const constants[] =
             {
               O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC, O_APPEND,
@@ -49,6 +57,14 @@ AC_DEFUN([gl_FCNTL_O_FLAGS],
           ]],
           [[
             int result = !constants;
+
+            {
+              int fd = open ("confdefs.h", O_SEARCH | O_DIRECTORY);
+              result |= ! (fd < 0 && errno == ENOTDIR);
+              if (0 <= fd)
+                close (fd);
+            }
+
             #if HAVE_SYMLINK
             {
               static char const sym[] = "conftest.sym";
@@ -112,31 +128,40 @@ AC_DEFUN([gl_FCNTL_O_FLAGS],
             }
             return result;]])],
        [gl_cv_header_working_fcntl_h=yes],
-       [case $? in #(
-        4) gl_cv_header_working_fcntl_h='no (bad O_NOFOLLOW)';; #(
-        64) gl_cv_header_working_fcntl_h='no (bad O_NOATIME)';; #(
-        68) gl_cv_header_working_fcntl_h='no (bad O_NOATIME, O_NOFOLLOW)';; #(
-         *) gl_cv_header_working_fcntl_h='no';;
-        esac],
-       [case "$host_os" in
-                             # Guess 'no' on native Windows.
-          mingw* | windows*) gl_cv_header_working_fcntl_h='no' ;;
-          *)                 gl_cv_header_working_fcntl_h=cross-compiling ;;
-        esac
-       ])
-    ])
+       [AS_CASE([$?],
+          [ 1], [gl_cv_header_working_fcntl_h="no (bad O_DIRECTORY)"],
+          [ 4], [gl_cv_header_working_fcntl_h="no (bad O_NOFOLLOW)"],
+          [ 5], [gl_cv_header_working_fcntl_h="no (bad O_DIRECTORY, 
O_NOFOLLOW)"],
+          [64], [gl_cv_header_working_fcntl_h="no (bad O_NOATIME)"],
+          [65], [gl_cv_header_working_fcntl_h="no (bad O_DIRECTORY, 
O_NOATIME)"],
+          [68], [gl_cv_header_working_fcntl_h="no (bad O_NOATIME, 
O_NOFOLLOW)"],
+          [69], [gl_cv_header_working_fcntl_h="no (bad O_DIRECTORY, O_NOATIME, 
O_NOFOLLOW)"],
+          [gl_cv_header_working_fcntl_h="no"])],
+       [AS_CASE([$host_os,$gl_cross_guess_normal],
+          # The O_DIRECTORY test is known to fail on Mac OS X 10.4.11 (2007)
+          # (see <https://bugs.gnu.org/78509#95>)
+          # and to succeed on macOS 12.6 [darwin21.6.0] (2021).
+          # For now, guess it fails on macOS 12.5 and earlier.
+          [darwin[[0-9]].*yes | darwin1[[0-9]]*.*yes | darwin20.*yes | \
+           darwin21.[[0-5]].*yes],
+             [gl_cv_header_working_fcntl_h="guessing no (bad O_DIRECTORY)"],
+          # Known to be "no" on native MS-Windows.
+          [mingw* | windows*],
+             [gl_cv_header_working_fcntl_h=no],
+          [gl_cv_header_working_fcntl_h=$gl_cross_guess_normal])])])
+
+  AS_CASE([$gl_cv_header_working_fcntl_h],
+    [*O_DIRECTORY* | *no], [ac_val=0], [ac_val=1])
+  AC_DEFINE_UNQUOTED([HAVE_WORKING_O_DIRECTORY], [$ac_val],
+    [Define to 1 if O_DIRECTORY works, 0 otherwise.])
 
-  case $gl_cv_header_working_fcntl_h in #(
-  *O_NOATIME* | no | cross-compiling) ac_val=0;; #(
-  *) ac_val=1;;
-  esac
+  AS_CASE([$gl_cv_header_working_fcntl_h],
+    [*O_NOATIME* | *no], [ac_val=0], [ac_val=1])
   AC_DEFINE_UNQUOTED([HAVE_WORKING_O_NOATIME], [$ac_val],
-    [Define to 1 if O_NOATIME works.])
+    [Define to 1 if O_NOATIME works, 0 otherwise.])
 
-  case $gl_cv_header_working_fcntl_h in #(
-  *O_NOFOLLOW* | no | cross-compiling) ac_val=0;; #(
-  *) ac_val=1;;
-  esac
+  AS_CASE([$gl_cv_header_working_fcntl_h],
+    [*O_NOFOLLOW* | *no], [ac_val=0], [ac_val=1])
   AC_DEFINE_UNQUOTED([HAVE_WORKING_O_NOFOLLOW], [$ac_val],
-    [Define to 1 if O_NOFOLLOW works.])
+    [Define to 1 if O_NOFOLLOW works, 0 otherwise.])
 ])
diff --git a/m4/open.m4 b/m4/open.m4
index 2bceddbdbe..dd3a805f5e 100644
--- a/m4/open.m4
+++ b/m4/open.m4
@@ -1,5 +1,5 @@
 # open.m4
-# serial 16
+# serial 17
 dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -10,6 +10,9 @@ AC_DEFUN([gl_FUNC_OPEN],
 [
   AC_REQUIRE([AC_CANONICAL_HOST])
   AC_REQUIRE([gl_PREPROC_O_CLOEXEC])
+  AC_REQUIRE([gl_FCNTL_O_FLAGS])
+  AS_CASE([$gl_cv_header_working_fcntl_h],
+    [*O_DIRECTORY* | *no], [REPLACE_OPEN=1])
   case "$host_os" in
     mingw* | windows* | pw*)
       REPLACE_OPEN=1
diff --git a/m4/openat.m4 b/m4/openat.m4
index eacc70f299..7557451cf1 100644
--- a/m4/openat.m4
+++ b/m4/openat.m4
@@ -1,5 +1,5 @@
 # openat.m4
-# serial 46
+# serial 47
 dnl Copyright (C) 2004-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -15,21 +15,14 @@ AC_DEFUN([gl_FUNC_OPENAT],
   AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   AC_CHECK_FUNCS_ONCE([openat])
+  AC_REQUIRE([gl_FCNTL_O_FLAGS])
   AC_REQUIRE([gl_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK])
   AC_REQUIRE([gl_PREPROC_O_CLOEXEC])
-  case 
$ac_cv_func_openat+$gl_cv_func_lstat_dereferences_slashed_symlink+$gl_cv_macro_O_CLOEXEC
 in
-  yes+*yes+yes)
-    ;;
-  yes+*)
-    # Solaris 10 lacks O_CLOEXEC.
-    # Solaris 9 has *at functions, but uniformly mishandles trailing
-    # slash in all of them.
-    REPLACE_OPENAT=1
-    ;;
-  *)
-    HAVE_OPENAT=0
-    ;;
-  esac
+  
AS_CASE([$ac_cv_func_openat+$gl_cv_header_working_fcntl_h+$gl_cv_func_lstat_dereferences_slashed_symlink+$gl_cv_macro_O_CLOEXEC],
+    [yes+*O_DIRECTORY*+*+* | yes+*no+*+*], [REPLACE_OPENAT=1],
+    [yes+*+*yes+yes], [],
+    [yes+*], [REPLACE_OPENAT=1],
+    [HAVE_OPENAT=0])
 ])
 
 # Prerequisites of lib/openat.c.
diff --git a/tests/test-open.h b/tests/test-open.h
index d253ef65b5..36823a4cbe 100644
--- a/tests/test-open.h
+++ b/tests/test-open.h
@@ -69,6 +69,11 @@ test_open (int (*func) (char const *, int, ...), bool print)
   ASSERT (func (BASE "file/", O_RDONLY) == -1);
   ASSERT (errno == ENOTDIR || errno == EISDIR || errno == EINVAL);
 
+  /* Cannot open non-directory with O_DIRECTORY.  */
+  errno = 0;
+  ASSERT (func (BASE "file", O_RDONLY | O_DIRECTORY) == -1);
+  ASSERT (errno == ENOTDIR);
+
   /* Directories cannot be opened for writing.  */
   errno = 0;
   ASSERT (func (".", O_WRONLY) == -1);
-- 
2.48.1


Reply via email to