summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2023-04-27 01:42:25 +0200
committerBruno Haible <bruno@clisp.org>2023-04-27 01:42:25 +0200
commit3f0950f65abb5162c42b51a9bb32c9e87deeb405 (patch)
treebd2794c98d44013cf67c6b39c0863054315ebd68
parentd70f555e34d9f4a9110e65dd5669fce701a61929 (diff)
downloadgnulib-3f0950f65abb5162c42b51a9bb32c9e87deeb405.tar.gz
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.
-rw-r--r--ChangeLog63
-rw-r--r--lib/closedir.c28
-rw-r--r--lib/dirent-private.h31
-rw-r--r--lib/dirent.in.h43
-rw-r--r--lib/dirfd.c17
-rw-r--r--lib/fchdir.c1
-rw-r--r--lib/fdopendir.c97
-rw-r--r--lib/opendir.c39
-rw-r--r--lib/readdir.c9
-rw-r--r--lib/rewinddir.c9
-rw-r--r--m4/closedir.m433
-rw-r--r--m4/dirent_h.m421
-rw-r--r--m4/dirfd.m429
-rw-r--r--m4/opendir.m435
-rw-r--r--m4/readdir.m48
-rw-r--r--m4/rewinddir.m48
-rw-r--r--modules/dirent3
-rw-r--r--modules/dirfd5
-rw-r--r--modules/fdopendir1
-rw-r--r--modules/readdir3
-rw-r--r--modules/rewinddir3
21 files changed, 372 insertions, 114 deletions
diff --git a/ChangeLog b/ChangeLog
index 7a377b243f..212d611c69 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,68 @@
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.
* modules/fchdir-tests (Depends-on): Add dup.
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 <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;
}
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 <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 */
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 <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
}
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 <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>
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 <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
@@ -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 <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
@@ -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 <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
@@ -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 <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])
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 <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.
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: