]> Savannah Git Hosting - gnulib.git/commitdiff
fdopendir: Fix fd leak and test failure on native Windows.
authorBruno Haible <bruno@clisp.org>
Wed, 26 Apr 2023 23:42:25 +0000 (01:42 +0200)
committerBruno Haible <bruno@clisp.org>
Wed, 26 Apr 2023 23:42:25 +0000 (01:42 +0200)
* 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 <stdlib.h> 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 <stdlib.h> always. Include <string.h>.
(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.

21 files changed:
ChangeLog
lib/closedir.c
lib/dirent-private.h
lib/dirent.in.h
lib/dirfd.c
lib/fchdir.c
lib/fdopendir.c
lib/opendir.c
lib/readdir.c
lib/rewinddir.c
m4/closedir.m4
m4/dirent_h.m4
m4/dirfd.m4
m4/opendir.m4
m4/readdir.m4
m4/rewinddir.m4
modules/dirent
modules/dirfd
modules/fdopendir
modules/readdir
modules/rewinddir

index 7a377b243fd169b9caab20901d79df071654d5f1..212d611c69dc6430e37daef067e47b3126edbafc 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,66 @@
+2023-04-26  Bruno Haible  <bruno@clisp.org>
+
+       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 <stdlib.h> 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 <stdlib.h> always. Include <string.h>.
+       (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  <bruno@clisp.org>
 
        fchdir tests: Fix test failure on native Windows.
index 0e004afeca5bb1d85577318590ebc7d3d2a97cbc..3777e9f70d1c98f54b8299923c2c5c8dbc97917b 100644 (file)
 # include <unistd.h>
 #endif
 
+#include <stdlib.h>
+
 #if HAVE_CLOSEDIR
 
 /* Override closedir(), to keep track of the open file descriptors.
    Needed because there is a function dirfd().  */
 
-#else
-
-# include <stdlib.h>
+#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;
 }
index f454e0e39a743fd15af249eb742b7755015a4e60..012b68371986bbdef7082ec9d7938ae4b0d64ac9 100644 (file)
 #ifndef _DIRENT_PRIVATE_H
 #define _DIRENT_PRIVATE_H 1
 
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
+#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 <windows.h>
 
 /* 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 */
index 40dea1a80e924814d1ae90deb3e3a7b4bf599e4b..d409a031ec815dbed9e42ec187c661db1d30d81e 100644 (file)
@@ -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
index b2b1d25cdbd183999f42a9dffb6134cfed282848..75b2163c35378cc11b06d109d77ce219c0164cb2 100644 (file)
 #include <dirent.h>
 #include <errno.h>
 
+#if GNULIB_defined_DIR
+# include "dirent-private.h"
+#endif
+
 #ifdef __KLIBC__
 # include <stdlib.h>
 # include <io.h>
@@ -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
 }
index 4e6209160571adac500da59b6c5feaba9bf94cd7..880b137ec66ce4b5d4a76401d914ebe4bd5ceb0c 100644 (file)
@@ -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;
index aa841e3e819fe667657fe9dc0ced33ea30b12945..0f43d6ff349a5a01b735daec37056306ca70683f 100644 (file)
 
 #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 <InnoTekLIBC/backend.h>
 
 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 <errno.h>
index bbe2c1dbcdb6c5f853dfcf7b35a1f2cf8120b980..ceb0e2829fe70dcf5eb01a2b63126d0fd7f7eccd 100644 (file)
 
 #else
 
-# include <stdlib.h>
-
-# include "dirent-private.h"
 # include "filename.h"
 
 #endif
 
+#include <stdlib.h>
+#include <string.h>
+
+#if GNULIB_defined_DIR
+# include "dirent-private.h"
+#endif
+
 #if REPLACE_FCHDIR
 # include <unistd.h>
 #endif
 
 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)
index 36eac8afbbe05038cff342a1a1d92ecc25b3f3fa..04dbba21bce6abef59c1e2eacf0e5aac5c9dd6fd 100644 (file)
@@ -22,7 +22,9 @@
 #include <errno.h>
 #include <stddef.h>
 
-#include "dirent-private.h"
+#if GNULIB_defined_DIR
+# include "dirent-private.h"
+#endif
 
 /* Don't assume that UNICODE is not defined.  */
 #undef FindNextFile
 
 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
 }
index 9988dc7be3764acc2b50db136febab6c8da94627..f200cc53c07fe0651a75558847a09527d24a0e11 100644 (file)
@@ -21,7 +21,9 @@
 
 #include <errno.h>
 
-#include "dirent-private.h"
+#if GNULIB_defined_DIR
+# include "dirent-private.h"
+#endif
 
 /* Don't assume that UNICODE is not defined.  */
 #undef FindFirstFile
 
 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
 }
index 9c15354c3d11cdd293bc648fa7461163976b7335..7e702def259c9e8f00f95e054ebb0df93dd5e753 100644 (file)
@@ -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
 ])
index 2a232a7622e6cf5c2551423e09c430574a6df759..b6c189c0d9f2cec111995945b3f6021860d8701f 100644 (file)
@@ -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 <dirent.h>
     ]], [alphasort closedir dirfd fdopendir opendir readdir rewinddir scandir])
 ])
 
+dnl Determine whether <dirent.h> 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])
index 2135535042b1295fa0d40161781722affd9cc65d..d1ee2c7f61defeed4bc320a713c05f6b265f8d60 100644 (file)
@@ -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 <dirent.h> 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.
index 2fb90b6d57fe3cfa9fa25b951f0f74c2a47ab580..2e9be769b534b0ead564c36ccafec5ec98678af5 100644 (file)
@@ -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
 ])
index 0a78739b3ccfc22ca52ff51f6cd1b40ccef658db..81337e2ffa25bb3a91a558bbf7fdf57a81b9c0b8 100644 (file)
@@ -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
 ])
index dc2c37d97a36ee0a9f859128d072952cd6408cfb..d0d24de8a6f4401382b22c275db75f38fa4e6e28 100644 (file)
@@ -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
 ])
index 8ae7bbfc4eb5e6c17570d39ce4d5afb56bc3af50..6f5a63ad66e878fd976be06d9566a35ab7e48a29 100644 (file)
@@ -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' \
index 0ffcf7ebbd7f4bef34fa0e19e6daa22479e57fe9..a87fa8b2e72ef21cb863a6c9ba19d585efc98393 100644 (file)
@@ -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
 ])
index 2dec7901679f344382bd284e33c929740be7d08e..7412254b6e2a311b4c84fb3f3447a04d6b90e19a 100644 (file)
@@ -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:
index cfa61c9c64427cf423a3aea1015b0455e06bbdc2..111fd307af6674461aec79f5952ea90af937ce0c 100644 (file)
@@ -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:
index 38cf6db0bc597d2837dca8c88b9f6fba2994588c..e4ccd2a6a5b854ed97c6b36860415b83c43fb3e0 100644 (file)
@@ -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: