From 3f0950f65abb5162c42b51a9bb32c9e87deeb405 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Thu, 27 Apr 2023 01:42:25 +0200 Subject: fdopendir: Fix fd leak and test failure on native Windows. * lib/dirent-private.h: On mingw, define 'struct gl_directory' as a wrapper around the original DIR. On MSVC, add an 'fd_to_close' field to 'struct gl_directory'. * lib/dirent.in.h (DIR): Define when DIR_HAS_FD_MEMBER is 0, i.e. on both mingw and MSVC. (GNULIB_defined_DIR): New macro. (opendir): Avoid incompatible redeclaration. (readdir): Consider REPLACE_READDIR. (rewinddir): Consider REPLACE_REWINDDIR. * m4/dirent_h.m4 (gl_DIRENT_DIR): New macro. (gl_DIRENT_H): Invoke it. (gl_DIRENT_H_DEFAULTS): Initialize REPLACE_READDIR, REPLACE_REWINDDIR. * modules/dirent (Makefile.am): Substitute DIR_HAS_FD_MEMBER, REPLACE_READDIR, REPLACE_REWINDDIR. -- * lib/dirfd.c (dirfd): If GNULIB_defined_DIR, just use the 'fd_to_close' field. * m4/dirfd.m4 (gl_FUNC_DIRFD): Set HAVE_DIRFD. Don't set REPLACE_DIRFD to 1 if HAVE_DIRFD is 0. If DIR_HAS_FD_MEMBER is 0, ensure dirfd.c gets compiled. * modules/dirfd (Files): Add lib/dirent-private.h. (Depends-on, configure.ac): Simplify conditions. -- * lib/closedir.c: Include always, for free(). (closedir): If GNULIB_defined_DIR, arrange to call close(dirfd(dirp)) at the end. On mingw, call free() of dirp. Prefer testing HAVE_DIRENT_H, for consistency with dirent.h. * m4/closedir.m4 (gl_FUNC_CLOSEDIR): Don't set REPLACE_CLOSEDIR to 1 if HAVE_CLOSEDIR is 0. If DIR_HAS_FD_MEMBER is 0, ensure closedir.c gets compiled. -- * lib/opendir.c: Include always. Include . (opendir): On mingw, allocate the 'struct gl_directory' through malloc. If GNULIB_defined_DIR, set the 'fd_to_close' field to -1. Prefer testing HAVE_DIRENT_H, for consistency with dirent.h. * m4/opendir.m4 (gl_FUNC_OPENDIR): Don't set REPLACE_OPENDIR to 1 if HAVE_OPENDIR is 0. If DIR_HAS_FD_MEMBER is 0, ensure opendir.c gets compiled. -- * lib/fdopendir.c (fdopendir): If GNULIB_defined_DIR, use a simple implementation based on opendir and the fchdir module. If __KLIBC__, don't define unused auxiliary functions. * modules/fdopendir (Files): Add lib/dirent-private.h. -- * lib/readdir.c (readdir): On mingw, redirect to the original readdir function. Prefer testing HAVE_DIRENT_H, for consistency with dirent.h. * m4/readdir.m4 (gl_FUNC_READDIR): If DIR_HAS_FD_MEMBER is 0, ensure readdir.c gets compiled. * modules/readdir (configure.ac): Consider REPLACE_READDIR. -- * lib/rewinddir.c (rewinddir): On mingw, redirect to the original rewinddir function. Prefer testing HAVE_DIRENT_H, for consistency with dirent.h. * m4/rewinddir.m4 (gl_FUNC_REWINDDIR): If DIR_HAS_FD_MEMBER is 0, ensure rewinddir.c gets compiled. * modules/rewinddir (configure.ac): Consider REPLACE_REWINDDIR. -- * lib/fchdir.c (dir_info_t): Remove a FIXME. --- ChangeLog | 63 ++++++++++++++++++++++++++++++++++ lib/closedir.c | 28 ++++++++++----- lib/dirent-private.h | 31 ++++++++++++++--- lib/dirent.in.h | 43 +++++++++++++++++++---- lib/dirfd.c | 17 +++++++-- lib/fchdir.c | 1 - lib/fdopendir.c | 97 +++++++++++++++++++++++++++++++++------------------- lib/opendir.c | 39 ++++++++++++++++++--- lib/readdir.c | 9 ++++- lib/rewinddir.c | 9 ++++- m4/closedir.m4 | 33 ++++++++++-------- m4/dirent_h.m4 | 21 +++++++++++- m4/dirfd.m4 | 29 ++++++++++------ m4/opendir.m4 | 35 ++++++++++--------- m4/readdir.m4 | 8 ++++- m4/rewinddir.m4 | 8 ++++- modules/dirent | 3 ++ modules/dirfd | 5 +-- modules/fdopendir | 1 + modules/readdir | 3 +- modules/rewinddir | 3 +- 21 files changed, 372 insertions(+), 114 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7a377b243f..212d611c69 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,66 @@ +2023-04-26 Bruno Haible + + fdopendir: Fix fd leak and test failure on native Windows. + -- + * lib/dirent-private.h: On mingw, define 'struct gl_directory' as a + wrapper around the original DIR. On MSVC, add an 'fd_to_close' field to + 'struct gl_directory'. + * lib/dirent.in.h (DIR): Define when DIR_HAS_FD_MEMBER is 0, i.e. on + both mingw and MSVC. + (GNULIB_defined_DIR): New macro. + (opendir): Avoid incompatible redeclaration. + (readdir): Consider REPLACE_READDIR. + (rewinddir): Consider REPLACE_REWINDDIR. + * m4/dirent_h.m4 (gl_DIRENT_DIR): New macro. + (gl_DIRENT_H): Invoke it. + (gl_DIRENT_H_DEFAULTS): Initialize REPLACE_READDIR, REPLACE_REWINDDIR. + * modules/dirent (Makefile.am): Substitute DIR_HAS_FD_MEMBER, + REPLACE_READDIR, REPLACE_REWINDDIR. + -- + * lib/dirfd.c (dirfd): If GNULIB_defined_DIR, just use the + 'fd_to_close' field. + * m4/dirfd.m4 (gl_FUNC_DIRFD): Set HAVE_DIRFD. Don't set REPLACE_DIRFD + to 1 if HAVE_DIRFD is 0. If DIR_HAS_FD_MEMBER is 0, ensure dirfd.c gets + compiled. + * modules/dirfd (Files): Add lib/dirent-private.h. + (Depends-on, configure.ac): Simplify conditions. + -- + * lib/closedir.c: Include always, for free(). + (closedir): If GNULIB_defined_DIR, arrange to call close(dirfd(dirp)) at + the end. On mingw, call free() of dirp. Prefer testing HAVE_DIRENT_H, + for consistency with dirent.h. + * m4/closedir.m4 (gl_FUNC_CLOSEDIR): Don't set REPLACE_CLOSEDIR to 1 if + HAVE_CLOSEDIR is 0. If DIR_HAS_FD_MEMBER is 0, ensure closedir.c gets + compiled. + -- + * lib/opendir.c: Include always. Include . + (opendir): On mingw, allocate the 'struct gl_directory' through malloc. + If GNULIB_defined_DIR, set the 'fd_to_close' field to -1. Prefer + testing HAVE_DIRENT_H, for consistency with dirent.h. + * m4/opendir.m4 (gl_FUNC_OPENDIR): Don't set REPLACE_OPENDIR to 1 if + HAVE_OPENDIR is 0. If DIR_HAS_FD_MEMBER is 0, ensure opendir.c gets + compiled. + -- + * lib/fdopendir.c (fdopendir): If GNULIB_defined_DIR, use a simple + implementation based on opendir and the fchdir module. If __KLIBC__, + don't define unused auxiliary functions. + * modules/fdopendir (Files): Add lib/dirent-private.h. + -- + * lib/readdir.c (readdir): On mingw, redirect to the original readdir + function. Prefer testing HAVE_DIRENT_H, for consistency with dirent.h. + * m4/readdir.m4 (gl_FUNC_READDIR): If DIR_HAS_FD_MEMBER is 0, ensure + readdir.c gets compiled. + * modules/readdir (configure.ac): Consider REPLACE_READDIR. + -- + * lib/rewinddir.c (rewinddir): On mingw, redirect to the original + rewinddir function. Prefer testing HAVE_DIRENT_H, for consistency with + dirent.h. + * m4/rewinddir.m4 (gl_FUNC_REWINDDIR): If DIR_HAS_FD_MEMBER is 0, ensure + rewinddir.c gets compiled. + * modules/rewinddir (configure.ac): Consider REPLACE_REWINDDIR. + -- + * lib/fchdir.c (dir_info_t): Remove a FIXME. + 2023-04-26 Bruno Haible fchdir tests: Fix test failure on native Windows. diff --git a/lib/closedir.c b/lib/closedir.c index 0e004afeca..3777e9f70d 100644 --- a/lib/closedir.c +++ b/lib/closedir.c @@ -23,31 +23,37 @@ # include #endif +#include + #if HAVE_CLOSEDIR /* Override closedir(), to keep track of the open file descriptors. Needed because there is a function dirfd(). */ -#else - -# include +#endif +#if GNULIB_defined_DIR # include "dirent-private.h" - #endif int closedir (DIR *dirp) +#undef closedir { -# if REPLACE_FCHDIR || REPLACE_DIRFD +#if GNULIB_defined_DIR || REPLACE_FCHDIR || defined __KLIBC__ int fd = dirfd (dirp); -# endif +#endif int retval; -#if HAVE_CLOSEDIR -# undef closedir +#if HAVE_DIRENT_H /* equivalent to HAVE_CLOSEDIR */ +# if GNULIB_defined_DIR + retval = closedir (dirp->real_dirp); + if (retval >= 0) + free (dirp); +# else retval = closedir (dirp); +# endif # ifdef __KLIBC__ if (!retval) @@ -63,9 +69,13 @@ closedir (DIR *dirp) #endif -#if REPLACE_FCHDIR +#if GNULIB_defined_DIR + if (retval >= 0) + close (fd); +#elif REPLACE_FCHDIR if (retval >= 0) _gl_unregister_fd (fd); #endif + return retval; } diff --git a/lib/dirent-private.h b/lib/dirent-private.h index f454e0e39a..012b683719 100644 --- a/lib/dirent-private.h +++ b/lib/dirent-private.h @@ -17,15 +17,36 @@ #ifndef _DIRENT_PRIVATE_H #define _DIRENT_PRIVATE_H 1 -#define WIN32_LEAN_AND_MEAN -#include +#if HAVE_DIRENT_H /* mingw */ + +# undef DIR + +struct gl_directory +{ + /* File descriptor to close during closedir(). + Needed for implementing fdopendir(). */ + int fd_to_close; + /* Pointer to the real DIR. */ + DIR *real_dirp; +}; + +/* Restore definition from dirent.h. */ +# define DIR struct gl_directory + +#else /* MSVC */ + +# define WIN32_LEAN_AND_MEAN +# include /* Don't assume that UNICODE is not defined. */ -#undef WIN32_FIND_DATA -#define WIN32_FIND_DATA WIN32_FIND_DATAA +# undef WIN32_FIND_DATA +# define WIN32_FIND_DATA WIN32_FIND_DATAA struct gl_directory { + /* File descriptor to close during closedir(). + Needed for implementing fdopendir(). */ + int fd_to_close; /* Status, or error code to produce in next readdir() call. -2 means the end of the directory is already reached, -1 means the entry was already filled by FindFirstFile, @@ -41,4 +62,6 @@ struct gl_directory char dir_name_mask[1]; }; +#endif + #endif /* _DIRENT_PRIVATE_H */ diff --git a/lib/dirent.in.h b/lib/dirent.in.h index 40dea1a80e..d409a031ec 100644 --- a/lib/dirent.in.h +++ b/lib/dirent.in.h @@ -56,11 +56,24 @@ struct dirent # define DT_LNK 10 /* symbolic link */ # define DT_SOCK 12 /* socket */ # define DT_WHT 14 /* whiteout */ -typedef struct gl_directory DIR; # define GNULIB_defined_struct_dirent 1 # endif #endif +#if !@DIR_HAS_FD_MEMBER@ +# if !GNULIB_defined_DIR +/* struct gl_directory is a type with a field 'int fd_to_close'. + It is needed for implementing fdopendir(). */ +struct gl_directory; +# if @HAVE_DIRENT_H@ +# define DIR struct gl_directory +# else +typedef struct gl_directory DIR; +# endif +# define GNULIB_defined_DIR 1 +# endif +#endif + /* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers that can be freed by passing them as the Ith argument to the function F. */ @@ -149,7 +162,7 @@ _GL_CXXALIAS_SYS (opendir, DIR *, (const char *dir_name)); # endif _GL_CXXALIASWARN (opendir); #else -# if @GNULIB_CLOSEDIR@ && __GNUC__ >= 11 && !defined opendir +# if @GNULIB_CLOSEDIR@ && !GNULIB_defined_DIR && __GNUC__ >= 11 && !defined opendir /* For -Wmismatched-dealloc: Associate opendir with closedir or rpl_closedir. */ _GL_FUNCDECL_SYS (opendir, DIR *, @@ -167,10 +180,19 @@ _GL_WARN_ON_USE (opendir, "opendir is not portable - " #endif #if @GNULIB_READDIR@ -# if !@HAVE_READDIR@ +# if @REPLACE_READDIR@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef readdir +# define readdir rpl_readdir +# endif +_GL_FUNCDECL_RPL (readdir, struct dirent *, (DIR *dirp) _GL_ARG_NONNULL ((1))); +_GL_CXXALIAS_RPL (readdir, struct dirent *, (DIR *dirp)); +# else +# if !@HAVE_READDIR@ _GL_FUNCDECL_SYS (readdir, struct dirent *, (DIR *dirp) _GL_ARG_NONNULL ((1))); -# endif +# endif _GL_CXXALIAS_SYS (readdir, struct dirent *, (DIR *dirp)); +# endif _GL_CXXALIASWARN (readdir); #elif defined GNULIB_POSIXCHECK # undef readdir @@ -181,10 +203,19 @@ _GL_WARN_ON_USE (readdir, "readdir is not portable - " #endif #if @GNULIB_REWINDDIR@ -# if !@HAVE_REWINDDIR@ +# if @REPLACE_REWINDDIR@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef rewinddir +# define rewinddir rpl_rewinddir +# endif +_GL_FUNCDECL_RPL (rewinddir, void, (DIR *dirp) _GL_ARG_NONNULL ((1))); +_GL_CXXALIAS_RPL (rewinddir, void, (DIR *dirp)); +# else +# if !@HAVE_REWINDDIR@ _GL_FUNCDECL_SYS (rewinddir, void, (DIR *dirp) _GL_ARG_NONNULL ((1))); -# endif +# endif _GL_CXXALIAS_SYS (rewinddir, void, (DIR *dirp)); +# endif _GL_CXXALIASWARN (rewinddir); #elif defined GNULIB_POSIXCHECK # undef rewinddir diff --git a/lib/dirfd.c b/lib/dirfd.c index b2b1d25cdb..75b2163c35 100644 --- a/lib/dirfd.c +++ b/lib/dirfd.c @@ -22,6 +22,10 @@ #include #include +#if GNULIB_defined_DIR +# include "dirent-private.h" +#endif + #ifdef __KLIBC__ # include # include @@ -78,11 +82,17 @@ _gl_unregister_dirp_fd (int fd) int dirfd (DIR *dir_p) { +#if GNULIB_defined_DIR + int fd = dir_p->fd_to_close; + if (fd == -1) + errno = EINVAL; + return fd; +#else int fd = DIR_TO_FD (dir_p); if (fd == -1) -#ifndef __KLIBC__ +# ifndef __KLIBC__ errno = ENOTSUP; -#else +# else { struct dirp_fd_list *dirp_fd; @@ -92,7 +102,8 @@ dirfd (DIR *dir_p) errno = EINVAL; } -#endif +# endif return fd; +#endif } diff --git a/lib/fchdir.c b/lib/fchdir.c index 4e62091605..880b137ec6 100644 --- a/lib/fchdir.c +++ b/lib/fchdir.c @@ -48,7 +48,6 @@ typedef struct { char *name; /* Absolute name of the directory, or NULL. */ - /* FIXME - add a DIR* member to make dirfd possible on mingw? */ } dir_info_t; static dir_info_t *dirs; static size_t dirs_allocated; diff --git a/lib/fdopendir.c b/lib/fdopendir.c index aa841e3e81..0f43d6ff34 100644 --- a/lib/fdopendir.c +++ b/lib/fdopendir.c @@ -25,44 +25,27 @@ #if !HAVE_FDOPENDIR -# include "openat.h" -# include "openat-priv.h" -# include "save-cwd.h" +# if GNULIB_defined_DIR +/* We are in control of the file descriptor of a DIR. */ -# if GNULIB_DIRENT_SAFER -# include "dirent--.h" -# endif - -# ifndef REPLACE_FCHDIR -# define REPLACE_FCHDIR 0 -# endif - -static DIR *fdopendir_with_dup (int, int, struct saved_cwd const *); -static DIR *fd_clone_opendir (int, struct saved_cwd const *); - -/* Replacement for POSIX fdopendir. +# include "dirent-private.h" - First, try to simulate it via opendir ("/proc/self/fd/..."). Failing - that, simulate it by using fchdir metadata, or by doing - save_cwd/fchdir/opendir(".")/restore_cwd. - If either the save_cwd or the restore_cwd fails (relatively unlikely), - then give a diagnostic and exit nonzero. - - If successful, the resulting stream is based on FD in - implementations where streams are based on file descriptors and in - applications where no other thread or signal handler allocates or - frees file descriptors. In other cases, consult dirfd on the result - to find out whether FD is still being used. +# if !REPLACE_FCHDIR +# error "unexpected configuration: GNULIB_defined_DIR but fchdir not replaced" +# endif - Otherwise, this function works just like POSIX fdopendir. +DIR * +fdopendir (int fd) +{ + char const *name = _gl_directory_name (fd); + DIR *dirp = name ? opendir (name) : NULL; + if (dirp != NULL) + dirp->fd_to_close = fd; + return dirp; +} - W A R N I N G: +# elif defined __KLIBC__ - Unlike other fd-related functions, this one places constraints on FD. - If this function returns successfully, FD is under control of the - dirent.h system, and the caller should not close or modify the state of - FD other than by the dirent.h functions. */ -# ifdef __KLIBC__ # include DIR * @@ -96,7 +79,48 @@ fdopendir (int fd) return dirp; } + # else +/* We are not in control of the file descriptor of a DIR, and therefore have to + play tricks with file descriptors before and after a call to opendir(). */ + +# include "openat.h" +# include "openat-priv.h" +# include "save-cwd.h" + +# if GNULIB_DIRENT_SAFER +# include "dirent--.h" +# endif + +# ifndef REPLACE_FCHDIR +# define REPLACE_FCHDIR 0 +# endif + +static DIR *fdopendir_with_dup (int, int, struct saved_cwd const *); +static DIR *fd_clone_opendir (int, struct saved_cwd const *); + +/* Replacement for POSIX fdopendir. + + First, try to simulate it via opendir ("/proc/self/fd/..."). Failing + that, simulate it by using fchdir metadata, or by doing + save_cwd/fchdir/opendir(".")/restore_cwd. + If either the save_cwd or the restore_cwd fails (relatively unlikely), + then give a diagnostic and exit nonzero. + + If successful, the resulting stream is based on FD in + implementations where streams are based on file descriptors and in + applications where no other thread or signal handler allocates or + frees file descriptors. In other cases, consult dirfd on the result + to find out whether FD is still being used. + + Otherwise, this function works just like POSIX fdopendir. + + W A R N I N G: + + Unlike other fd-related functions, this one places constraints on FD. + If this function returns successfully, FD is under control of the + dirent.h system, and the caller should not close or modify the state of + FD other than by the dirent.h functions. */ DIR * fdopendir (int fd) { @@ -119,7 +143,6 @@ fdopendir (int fd) return dir; } -# endif /* Like fdopendir, except that if OLDER_DUPFD is not -1, it is known to be a dup of FD which is less than FD - 1 and which will be @@ -188,7 +211,7 @@ fd_clone_opendir (int fd, struct saved_cwd const *cwd) if (proc_file != buf) free (proc_file); } -# if REPLACE_FCHDIR +# if REPLACE_FCHDIR if (! dir && EXPECTED_ERRNO (saved_errno)) { char const *name = _gl_directory_name (fd); @@ -203,7 +226,7 @@ fd_clone_opendir (int fd, struct saved_cwd const *cwd) return dp; } -# endif +# endif errno = saved_errno; return dir; } @@ -223,6 +246,8 @@ fd_clone_opendir (int fd, struct saved_cwd const *cwd) } } +# endif + #else /* HAVE_FDOPENDIR */ # include diff --git a/lib/opendir.c b/lib/opendir.c index bbe2c1dbcd..ceb0e2829f 100644 --- a/lib/opendir.c +++ b/lib/opendir.c @@ -29,13 +29,17 @@ #else -# include - -# include "dirent-private.h" # include "filename.h" #endif +#include +#include + +#if GNULIB_defined_DIR +# include "dirent-private.h" +#endif + #if REPLACE_FCHDIR # include #endif @@ -57,14 +61,37 @@ DIR * opendir (const char *dir_name) +#undef opendir { -#if HAVE_OPENDIR -# undef opendir +#if HAVE_DIRENT_H /* equivalent to HAVE_OPENDIR */ DIR *dirp; +# if GNULIB_defined_DIR +# undef DIR + + dirp = (struct gl_directory *) malloc (sizeof (struct gl_directory)); + if (dirp == NULL) + { + errno = ENOMEM; + return NULL; + } + + DIR *real_dirp = opendir (dir_name); + if (real_dirp == NULL) + { + int saved_errno = errno; + free (dirp); + errno = saved_errno; + return NULL; + } + + dirp->fd_to_close = -1; + dirp->real_dirp = real_dirp; +# else dirp = opendir (dir_name); if (dirp == NULL) return NULL; +# endif # ifdef __KLIBC__ { @@ -82,6 +109,7 @@ opendir (const char *dir_name) } } # endif + #else char dir_name_mask[MAX_PATH + 1 + 1 + 1]; @@ -154,6 +182,7 @@ opendir (const char *dir_name) errno = ENOMEM; return NULL; } + dirp->fd_to_close = -1; dirp->status = status; dirp->current = current; if (status == -1) diff --git a/lib/readdir.c b/lib/readdir.c index 36eac8afbb..04dbba21bc 100644 --- a/lib/readdir.c +++ b/lib/readdir.c @@ -22,7 +22,9 @@ #include #include -#include "dirent-private.h" +#if GNULIB_defined_DIR +# include "dirent-private.h" +#endif /* Don't assume that UNICODE is not defined. */ #undef FindNextFile @@ -30,7 +32,11 @@ struct dirent * readdir (DIR *dirp) +#undef readdir { +#if HAVE_DIRENT_H /* equivalent to HAVE_READDIR */ + return readdir (dirp->real_dirp); +#else char type; struct dirent *result; @@ -99,4 +105,5 @@ readdir (DIR *dirp) result->d_type = type; return result; +#endif } diff --git a/lib/rewinddir.c b/lib/rewinddir.c index 9988dc7be3..f200cc53c0 100644 --- a/lib/rewinddir.c +++ b/lib/rewinddir.c @@ -21,7 +21,9 @@ #include -#include "dirent-private.h" +#if GNULIB_defined_DIR +# include "dirent-private.h" +#endif /* Don't assume that UNICODE is not defined. */ #undef FindFirstFile @@ -29,7 +31,11 @@ void rewinddir (DIR *dirp) +#undef rewinddir { +#if HAVE_DIRENT_H /* equivalent to HAVE_REWINDDIR */ + rewinddir (dirp->real_dirp); +#else /* Like in closedir(). */ if (dirp->current != INVALID_HANDLE_VALUE) FindClose (dirp->current); @@ -50,4 +56,5 @@ rewinddir (DIR *dirp) break; } } +#endif } diff --git a/m4/closedir.m4 b/m4/closedir.m4 index 9c15354c3d..7e702def25 100644 --- a/m4/closedir.m4 +++ b/m4/closedir.m4 @@ -1,4 +1,4 @@ -# closedir.m4 serial 6 +# closedir.m4 serial 7 dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -12,20 +12,23 @@ AC_DEFUN([gl_FUNC_CLOSEDIR], AC_CHECK_FUNCS([closedir]) if test $ac_cv_func_closedir = no; then HAVE_CLOSEDIR=0 - fi - dnl Replace closedir() for supporting the gnulib-defined fchdir() function, - dnl to keep fchdir's bookkeeping up-to-date. - m4_ifdef([gl_FUNC_FCHDIR], [ - gl_TEST_FCHDIR - if test $HAVE_FCHDIR = 0; then - if test $HAVE_CLOSEDIR = 1; then + else + dnl Replace closedir() on native Windows, to support fdopendir(). + AC_REQUIRE([gl_DIRENT_DIR]) + if test $DIR_HAS_FD_MEMBER = 0; then + REPLACE_CLOSEDIR=1 + fi + dnl Replace closedir() for supporting the gnulib-defined dirfd() function. + case $host_os in + os2*) REPLACE_CLOSEDIR=1 ;; + esac + dnl Replace closedir() for supporting the gnulib-defined fchdir() function, + dnl to keep fchdir's bookkeeping up-to-date. + m4_ifdef([gl_FUNC_FCHDIR], [ + gl_TEST_FCHDIR + if test $HAVE_FCHDIR = 0; then REPLACE_CLOSEDIR=1 fi - fi - ]) - dnl Replace closedir() for supporting the gnulib-defined dirfd() function. - case $host_os,$HAVE_CLOSEDIR in - os2*,1) - REPLACE_CLOSEDIR=1;; - esac + ]) + fi ]) diff --git a/m4/dirent_h.m4 b/m4/dirent_h.m4 index 2a232a7622..b6c189c0d9 100644 --- a/m4/dirent_h.m4 +++ b/m4/dirent_h.m4 @@ -1,4 +1,4 @@ -# dirent_h.m4 serial 19 +# dirent_h.m4 serial 20 dnl Copyright (C) 2008-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -21,12 +21,29 @@ AC_DEFUN_ONCE([gl_DIRENT_H], fi AC_SUBST([HAVE_DIRENT_H]) + gl_DIRENT_DIR + dnl Check for declarations of anything we want to poison if the dnl corresponding gnulib module is not in use. gl_WARN_ON_USE_PREPARE([[#include ]], [alphasort closedir dirfd fdopendir opendir readdir rewinddir scandir]) ]) +dnl Determine whether needs to override the DIR type. +AC_DEFUN_ONCE([gl_DIRENT_DIR], +[ + dnl Set DIR_HAS_FD_MEMBER if dirfd() works, i.e. not always returns -1, + dnl or has the __KLIBC__ workaround as in lib/dirfd.c. + dnl We could use the findings from gl_FUNC_DIRFD and gl_PREREQ_DIRFD, but + dnl it's simpler since we know the affected platforms. + AC_REQUIRE([AC_CANONICAL_HOST]) + case "$host_os" in + mingw*) DIR_HAS_FD_MEMBER=0 ;; + *) DIR_HAS_FD_MEMBER=1 ;; + esac + AC_SUBST([DIR_HAS_FD_MEMBER]) +]) + # gl_DIRENT_MODULE_INDICATOR([modulename]) # sets the shell variable that indicates the presence of the given module # to a C preprocessor expression that will evaluate to 1. @@ -73,6 +90,8 @@ AC_DEFUN([gl_DIRENT_H_DEFAULTS], HAVE_SCANDIR=1; AC_SUBST([HAVE_SCANDIR]) HAVE_ALPHASORT=1; AC_SUBST([HAVE_ALPHASORT]) REPLACE_OPENDIR=0; AC_SUBST([REPLACE_OPENDIR]) + REPLACE_READDIR=0; AC_SUBST([REPLACE_READDIR]) + REPLACE_REWINDDIR=0; AC_SUBST([REPLACE_REWINDDIR]) REPLACE_CLOSEDIR=0; AC_SUBST([REPLACE_CLOSEDIR]) REPLACE_DIRFD=0; AC_SUBST([REPLACE_DIRFD]) REPLACE_FDOPENDIR=0; AC_SUBST([REPLACE_FDOPENDIR]) diff --git a/m4/dirfd.m4 b/m4/dirfd.m4 index 2135535042..d1ee2c7f61 100644 --- a/m4/dirfd.m4 +++ b/m4/dirfd.m4 @@ -1,4 +1,4 @@ -# serial 26 -*- Autoconf -*- +# serial 27 -*- Autoconf -*- dnl Find out how to get the file descriptor associated with an open DIR*. @@ -12,7 +12,7 @@ dnl From Jim Meyering AC_DEFUN([gl_FUNC_DIRFD], [ AC_REQUIRE([gl_DIRENT_H_DEFAULTS]) - AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_REQUIRE([AC_CANONICAL_HOST]) dnl Persuade glibc to declare dirfd(). AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) @@ -36,15 +36,24 @@ AC_DEFUN([gl_FUNC_DIRFD], [gl_cv_func_dirfd_macro=yes], [gl_cv_func_dirfd_macro=no])]) - # Use the replacement if we have no function or macro with that name, - # or if OS/2 kLIBC whose dirfd() does not work. - # Replace only if the system declares dirfd already. - case $ac_cv_func_dirfd,$gl_cv_func_dirfd_macro,$host_os,$ac_cv_have_decl_dirfd in - no,no,*,yes | *,*,os2*,yes) + if test $ac_cv_func_dirfd = no && test $gl_cv_func_dirfd_macro = no; then + HAVE_DIRFD=0 + else + HAVE_DIRFD=1 + dnl Replace only if the system declares dirfd already. + if test $ac_cv_have_decl_dirfd = yes; then REPLACE_DIRFD=1 - AC_DEFINE([REPLACE_DIRFD], [1], - [Define to 1 if gnulib's dirfd() replacement is used.]);; - esac + fi + dnl Replace dirfd() on native Windows, to support fdopendir(). + AC_REQUIRE([gl_DIRENT_DIR]) + if test $DIR_HAS_FD_MEMBER = 0; then + REPLACE_DIRFD=1 + fi + dnl OS/2 kLIBC dirfd() does not work. + case "$host_os" in + os2*) REPLACE_DIRFD=1 ;; + esac + fi ]) dnl Prerequisites of lib/dirfd.c. diff --git a/m4/opendir.m4 b/m4/opendir.m4 index 2fb90b6d57..2e9be769b5 100644 --- a/m4/opendir.m4 +++ b/m4/opendir.m4 @@ -1,4 +1,4 @@ -# opendir.m4 serial 5 +# opendir.m4 serial 6 dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -12,21 +12,24 @@ AC_DEFUN([gl_FUNC_OPENDIR], AC_CHECK_FUNCS([opendir]) if test $ac_cv_func_opendir = no; then HAVE_OPENDIR=0 - fi - dnl Replace opendir() for supporting the gnulib-defined fchdir() function, - dnl to keep fchdir's bookkeeping up-to-date. - m4_ifdef([gl_FUNC_FCHDIR], [ - gl_TEST_FCHDIR - if test $HAVE_FCHDIR = 0; then - if test $HAVE_OPENDIR = 1; then + else + dnl Replace opendir() on native Windows, to support fdopendir(). + AC_REQUIRE([gl_DIRENT_DIR]) + if test $DIR_HAS_FD_MEMBER = 0; then + REPLACE_OPENDIR=1 + fi + dnl Replace opendir() on OS/2 kLIBC to support dirfd() function replaced + dnl by gnulib. + case $host_os in + os2*) REPLACE_OPENDIR=1 ;; + esac + dnl Replace opendir() for supporting the gnulib-defined fchdir() function, + dnl to keep fchdir's bookkeeping up-to-date. + m4_ifdef([gl_FUNC_FCHDIR], [ + gl_TEST_FCHDIR + if test $HAVE_FCHDIR = 0; then REPLACE_OPENDIR=1 fi - fi - ]) - dnl Replace opendir() on OS/2 kLIBC to support dirfd() function replaced - dnl by gnulib. - case $host_os,$HAVE_OPENDIR in - os2*,1) - REPLACE_OPENDIR=1;; - esac + ]) + fi ]) diff --git a/m4/readdir.m4 b/m4/readdir.m4 index 0a78739b3c..81337e2ffa 100644 --- a/m4/readdir.m4 +++ b/m4/readdir.m4 @@ -1,4 +1,4 @@ -# readdir.m4 serial 1 +# readdir.m4 serial 2 dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -11,5 +11,11 @@ AC_DEFUN([gl_FUNC_READDIR], AC_CHECK_FUNCS([readdir]) if test $ac_cv_func_readdir = no; then HAVE_READDIR=0 + else + dnl Replace readdir() on native Windows, to support fdopendir(). + AC_REQUIRE([gl_DIRENT_DIR]) + if test $DIR_HAS_FD_MEMBER = 0; then + REPLACE_READDIR=1 + fi fi ]) diff --git a/m4/rewinddir.m4 b/m4/rewinddir.m4 index dc2c37d97a..d0d24de8a6 100644 --- a/m4/rewinddir.m4 +++ b/m4/rewinddir.m4 @@ -1,4 +1,4 @@ -# rewinddir.m4 serial 1 +# rewinddir.m4 serial 2 dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -11,5 +11,11 @@ AC_DEFUN([gl_FUNC_REWINDDIR], AC_CHECK_FUNCS([rewinddir]) if test $ac_cv_func_rewinddir = no; then HAVE_REWINDDIR=0 + else + dnl Replace rewinddir() on native Windows, to support fdopendir(). + AC_REQUIRE([gl_DIRENT_DIR]) + if test $DIR_HAS_FD_MEMBER = 0; then + REPLACE_REWINDDIR=1 + fi fi ]) diff --git a/modules/dirent b/modules/dirent index 8ae7bbfc4e..6f5a63ad66 100644 --- a/modules/dirent +++ b/modules/dirent @@ -33,6 +33,7 @@ dirent.h: dirent.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ -e 's|@''NEXT_DIRENT_H''@|$(NEXT_DIRENT_H)|g' \ + -e 's/@''DIR_HAS_FD_MEMBER''@/$(DIR_HAS_FD_MEMBER)/g' \ -e 's/@''GNULIB_OPENDIR''@/$(GNULIB_OPENDIR)/g' \ -e 's/@''GNULIB_READDIR''@/$(GNULIB_READDIR)/g' \ -e 's/@''GNULIB_REWINDDIR''@/$(GNULIB_REWINDDIR)/g' \ @@ -51,6 +52,8 @@ dirent.h: dirent.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's|@''HAVE_SCANDIR''@|$(HAVE_SCANDIR)|g' \ -e 's|@''HAVE_ALPHASORT''@|$(HAVE_ALPHASORT)|g' \ -e 's|@''REPLACE_OPENDIR''@|$(REPLACE_OPENDIR)|g' \ + -e 's|@''REPLACE_READDIR''@|$(REPLACE_READDIR)|g' \ + -e 's|@''REPLACE_REWINDDIR''@|$(REPLACE_REWINDDIR)|g' \ -e 's|@''REPLACE_CLOSEDIR''@|$(REPLACE_CLOSEDIR)|g' \ -e 's|@''REPLACE_DIRFD''@|$(REPLACE_DIRFD)|g' \ -e 's|@''REPLACE_FDOPENDIR''@|$(REPLACE_FDOPENDIR)|g' \ diff --git a/modules/dirfd b/modules/dirfd index 0ffcf7ebbd..a87fa8b2e7 100644 --- a/modules/dirfd +++ b/modules/dirfd @@ -3,17 +3,18 @@ Retrieving the file descriptor of an open directory stream. (Unportable.) Files: lib/dirfd.c +lib/dirent-private.h m4/dirfd.m4 Depends-on: dirent extensions -errno [test $ac_cv_func_dirfd = no && test $gl_cv_func_dirfd_macro = no || test $REPLACE_DIRFD = 1] +errno [test $HAVE_DIRFD = 0 || test $REPLACE_DIRFD = 1] configure.ac: gl_FUNC_DIRFD gl_CONDITIONAL([GL_COND_OBJ_DIRFD], - [test $ac_cv_func_dirfd = no && test $gl_cv_func_dirfd_macro = no || test $REPLACE_DIRFD = 1]) + [test $HAVE_DIRFD = 0 || test $REPLACE_DIRFD = 1]) AM_COND_IF([GL_COND_OBJ_DIRFD], [ gl_PREREQ_DIRFD ]) diff --git a/modules/fdopendir b/modules/fdopendir index 2dec790167..7412254b6e 100644 --- a/modules/fdopendir +++ b/modules/fdopendir @@ -3,6 +3,7 @@ Open a directory stream from a file descriptor. Files: lib/fdopendir.c +lib/dirent-private.h m4/fdopendir.m4 Depends-on: diff --git a/modules/readdir b/modules/readdir index cfa61c9c64..111fd307af 100644 --- a/modules/readdir +++ b/modules/readdir @@ -12,7 +12,8 @@ largefile configure.ac: gl_FUNC_READDIR -gl_CONDITIONAL([GL_COND_OBJ_READDIR], [test $HAVE_READDIR = 0]) +gl_CONDITIONAL([GL_COND_OBJ_READDIR], + [test $HAVE_READDIR = 0 || test $REPLACE_READDIR = 1]) gl_DIRENT_MODULE_INDICATOR([readdir]) Makefile.am: diff --git a/modules/rewinddir b/modules/rewinddir index 38cf6db0bc..e4ccd2a6a5 100644 --- a/modules/rewinddir +++ b/modules/rewinddir @@ -13,7 +13,8 @@ largefile configure.ac: gl_FUNC_REWINDDIR -gl_CONDITIONAL([GL_COND_OBJ_REWINDDIR], [test $HAVE_REWINDDIR = 0]) +gl_CONDITIONAL([GL_COND_OBJ_REWINDDIR], + [test $HAVE_REWINDDIR = 0 || test $REPLACE_REWINDDIR = 1]) gl_DIRENT_MODULE_INDICATOR([rewinddir]) Makefile.am: -- cgit v1.2.1