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)