summaryrefslogtreecommitdiff
path: root/lib/opendir.c
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 /lib/opendir.c
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.
Diffstat (limited to 'lib/opendir.c')
-rw-r--r--lib/opendir.c39
1 files changed, 34 insertions, 5 deletions
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)