Paul Eggert wrote:
> +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.

This patch, unfortunately, causes a regression: The test 'test-fts' now
fails on native Windows.


FAIL: test-fts
==============

0 needles found (should be 4)
FAIL test-fts.exe (exit status: 1)


When I single-step through the test, I see that it does not even recurse
through the directory hierarchy. It opens only "t-fts.tmp" and that's it.

The cause is that before the patch, in config.h, we have
  HAVE_WORKING_O_NOATIME = 0
  HAVE_WORKING_O_NOFOLLOW = 0
and after the patch
  HAVE_WORKING_O_NOATIME = 1
  HAVE_WORKING_O_NOFOLLOW = 1
  HAVE_WORKING_O_DIRECTORY = 0
The problem is that the "checking for working fcntl.h" encounters a compilation
error (due to O_NOCTTY, O_NONBLOCK, O_SYNC that are not defined on mingw), and
the exit code 1 from the compiler gets mis-interpreted.

When I fix m4/fcntl-o.m4 to get
  HAVE_WORKING_O_NOATIME = 0
  HAVE_WORKING_O_NOFOLLOW = 0
  HAVE_WORKING_O_DIRECTORY = 0
then test-fts still fails. This time it recurses through the subdirectories,
but it fails just before the _gl_register_fd call, in open.c.

With the two fixes from the patch below, test-fts finally works again.


2025-06-03  Bruno Haible  <br...@clisp.org>

        fcntl-h, open: Fix two regressions on native Windows (regr. 2025-05-26).
        * m4/fcntl-o.m4 (gl_FCNTL_O_FLAGS): Reshuffle the exit code bits, so
        that a compilation failure produces the "no" result.
        * lib/open.c (open): Don't pass the O_DIRECTORY flag when doing
        recursion with /dev/null.

diff --git a/lib/open.c b/lib/open.c
index 3da2dce072..8356c14f5b 100644
--- a/lib/open.c
+++ b/lib/open.c
@@ -202,7 +202,7 @@ open (const char *filename, int flags, ...)
               && S_ISDIR (statbuf.st_mode)))
         {
           /* Maximum recursion depth of 1.  */
-          fd = open ("/dev/null", flags, mode);
+          fd = open ("/dev/null", flags & ~O_DIRECTORY, mode);
           if (0 <= fd)
             fd = _gl_register_fd (fd, filename);
         }
diff --git a/m4/fcntl-o.m4 b/m4/fcntl-o.m4
index 9c19b582f8..38321e5964 100644
--- a/m4/fcntl-o.m4
+++ b/m4/fcntl-o.m4
@@ -1,5 +1,5 @@
 # fcntl-o.m4
-# serial 10
+# serial 11
 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,
@@ -57,42 +57,41 @@ 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";
               if (symlink ("/dev/null", sym) != 0)
-                result |= 2;
+                result |= 1;
               else
                 {
                   int fd = open (sym, O_WRONLY | O_NOFOLLOW | O_CREAT, 0);
                   if (fd >= 0)
                     {
                       close (fd);
-                      result |= 4;
+                      result |= 2;
                     }
                 }
               if (unlink (sym) != 0 || symlink (".", sym) != 0)
-                result |= 2;
+                result |= 1;
               else
                 {
                   int fd = open (sym, O_RDONLY | O_NOFOLLOW);
                   if (fd >= 0)
                     {
                       close (fd);
-                      result |= 4;
+                      result |= 2;
                     }
                 }
               unlink (sym);
             }
             #endif
+            {
+              int fd = open ("confdefs.h", O_SEARCH | O_DIRECTORY);
+              if (!(fd < 0 && errno == ENOTDIR))
+                result |= 4;
+              if (0 <= fd)
+                close (fd);
+            }
             {
               static char const file[] = "confdefs.h";
               int fd = open (file, O_RDONLY | O_NOATIME);
@@ -129,13 +128,16 @@ AC_DEFUN([gl_FCNTL_O_FLAGS]
             return result;]])],
        [gl_cv_header_working_fcntl_h=yes],
        [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)"],
+          dnl We cannot catch exit code 1 here, because exit code 1 can occur
+          dnl through a compilation error (e.g. when O_NOCTTY, O_NONBLOCK, 
O_SYNC
+          dnl are not defined) or when result = 1.
+          [ 2], [gl_cv_header_working_fcntl_h="no (bad O_NOFOLLOW)"],
+          [ 4], [gl_cv_header_working_fcntl_h="no (bad O_DIRECTORY)"],
+          [ 6], [gl_cv_header_working_fcntl_h="no (bad O_NOFOLLOW, 
O_DIRECTORY)"],
           [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)"],
+          [66], [gl_cv_header_working_fcntl_h="no (bad O_NOFOLLOW, 
O_NOATIME)"],
+          [68], [gl_cv_header_working_fcntl_h="no (bad O_DIRECTORY, 
O_NOATIME)"],
+          [70], [gl_cv_header_working_fcntl_h="no (bad O_NOFOLLOW, 
O_DIRECTORY, O_NOATIME)"],
           [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)




Reply via email to