* lib/closedir.c (closedir): Unregister fd if closedir() succeeds.
* lib/dirent.in.h (_gl_register_dirp_fd, _gl_unregister_dirp_fd):
Declare on kLIBC.
* lib/dirfd.c (struct dirp_fd_list): New. Structures to keep track of
fd associated with dirp.
(_gl_register_dirp_fd): New. Register fd associated with dirp to
dirp_fd_list.
(_gl_unregister_dirp_fd): New. Unregister fd with closing it.
(dirfd): Implemented for kLIBC.
* lib/fdopendir.c (fdopendir): Implemented for kLIBC.
* lib/opendir.c (opendir): New. Register fd and dirp pair if open()
succeeds.
* m4/closedir.m4 (gl_FUNC_CLOSEDIR): Replace if OS/2.
* m4/dirfd.m4 (gl_FUNC_DIRFD): Likewise.
(REPLACE_DIRFD): Define to 1 if replaced.
* m4/opendir.m4 (gl_FUNC_OPENDIR): Likewise.
* modules/closedir (Depends-on): Add dirfd.
* modules/dirfd (Depends-on): Add 'test $REPLACE_DIRFD = 1' to errno
condition.
(configure.ac): Add dirfd to LIBOBJS if $REPLACE_DIRFD = 1 as well.
* modules/opendir (Depends-on): Add dirfd.
---
lib/closedir.c | 6 ++++-
lib/dirent.in.h | 7 ++++++
lib/dirfd.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/fdopendir.c | 36 ++++++++++++++++++++++++++++++
lib/opendir.c | 21 +++++++++++++++++
m4/closedir.m4 | 9 +++++++-
m4/dirfd.m4 | 10 ++++++---
m4/opendir.m4 | 9 +++++++-
modules/closedir | 1 +
modules/dirfd | 5 +++--
modules/opendir | 1 +
11 files changed, 165 insertions(+), 8 deletions(-)
diff --git a/lib/closedir.c b/lib/closedir.c
index c0298bc..30d1290 100644
--- a/lib/closedir.c
+++ b/lib/closedir.c
@@ -39,7 +39,7 @@
int
closedir (DIR *dirp)
{
-# if REPLACE_FCHDIR
+# if REPLACE_FCHDIR || REPLACE_DIRFD
int fd = dirfd (dirp);
# endif
int retval;
@@ -49,6 +49,10 @@ closedir (DIR *dirp)
retval = closedir (dirp);
+# ifdef __KLIBC__
+ if (!retval)
+ _gl_unregister_dirp_fd (fd);
+# endif
#else
if (dirp->current != INVALID_HANDLE_VALUE)
diff --git a/lib/dirent.in.h b/lib/dirent.in.h
index 4c62737..65482d7 100644
--- a/lib/dirent.in.h
+++ b/lib/dirent.in.h
@@ -158,6 +158,13 @@ _GL_WARN_ON_USE (closedir, "closedir is not portable - "
# endif
_GL_FUNCDECL_RPL (dirfd, int, (DIR *) _GL_ARG_NONNULL ((1)));
_GL_CXXALIAS_RPL (dirfd, int, (DIR *));
+
+# ifdef __KLIBC__
+/* Gnulib internal hooks needed to maintain the dirfd metadata. */
+_GL_EXTERN_C int _gl_register_dirp_fd (int fd, DIR *dirp)
+ _GL_ARG_NONNULL ((2));
+_GL_EXTERN_C void _gl_unregister_dirp_fd (int fd);
+# endif
# else
# if defined __cplusplus && defined GNULIB_NAMESPACE && defined dirfd
/* dirfd is defined as a macro and not as a function.
diff --git a/lib/dirfd.c b/lib/dirfd.c
index 1ea2a63..2b659f4 100644
--- a/lib/dirfd.c
+++ b/lib/dirfd.c
@@ -22,11 +22,79 @@
#include <dirent.h>
#include <errno.h>
+#ifdef __KLIBC__
+# include <stdlib.h>
+# include <io.h>
+
+static struct dirp_fd_list
+{
+ DIR *dirp;
+ int fd;
+ struct dirp_fd_list *next;
+} *dirp_fd_start = NULL;
+
+/* Register fd associated with dirp to dirp_fd_list. */
+int
+_gl_register_dirp_fd (int fd, DIR *dirp)
+{
+ struct dirp_fd_list *new_dirp_fd;
+
+ new_dirp_fd = malloc (sizeof (*new_dirp_fd));
+ if (!new_dirp_fd)
+ return -1;
+
+ new_dirp_fd->dirp = dirp;
+ new_dirp_fd->fd = fd;
+ new_dirp_fd->next = dirp_fd_start;
+
+ dirp_fd_start = new_dirp_fd;
+
+ return 0;
+}
+
+/* Unregister fd from dirp_fd_list with closing it */
+void
+_gl_unregister_dirp_fd (int fd)
+{
+ struct dirp_fd_list *dirp_fd;
+ struct dirp_fd_list *dirp_fd_prev;
+
+ for (dirp_fd_prev = NULL, dirp_fd = dirp_fd_start; dirp_fd;
+ dirp_fd_prev = dirp_fd, dirp_fd = dirp_fd->next)
+ {
+ if (dirp_fd->fd == fd)
+ {
+ if (dirp_fd_prev)
+ dirp_fd_prev->next = dirp_fd->next;
+ else /* dirp_fd == dirp_fd_start */
+ dirp_fd_start = dirp_fd_start->next;
+
+ close (fd);
+ free (dirp_fd);
+ break;
+ }
+ }
+}
+#endif
+
int
dirfd (DIR *dir_p)
{
int fd = DIR_TO_FD (dir_p);
if (fd == -1)
+#ifndef __KLIBC__
errno = ENOTSUP;
+#else
+ {
+ struct dirp_fd_list *dirp_fd;
+
+ for (dirp_fd = dirp_fd_start; dirp_fd; dirp_fd = dirp_fd->next)
+ if (dirp_fd->dirp == dir_p)
+ return dirp_fd->fd;
+
+ errno = EINVAL;
+ }
+#endif
+
return fd;
}
diff --git a/lib/fdopendir.c b/lib/fdopendir.c
index f30ab24..c1f4dcb 100644
--- a/lib/fdopendir.c
+++ b/lib/fdopendir.c
@@ -62,6 +62,41 @@ static DIR *fd_clone_opendir (int, struct saved_cwd const *);
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 *
+fdopendir (int fd)
+{
+ char path[_MAX_PATH];
+ DIR *dirp;
+
+ /* Get a path from fd */
+ if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
+ return NULL;
+
+ dirp = opendir (path);
+ if (!dirp)
+ return NULL;
+
+ /* Unregister fd registered by opendir() */
+ _gl_unregister_dirp_fd (dirfd (dirp));
+
+ /* Register our fd */
+ if (_gl_register_dirp_fd (fd, dirp))
+ {
+ int saved_errno = errno;
+
+ closedir (dirp);
+
+ errno = saved_errno;
+
+ dirp = NULL;
+ }
+
+ return dirp;
+}
+# else
DIR *
fdopendir (int fd)
{
@@ -84,6 +119,7 @@ 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
diff --git a/lib/opendir.c b/lib/opendir.c
index 1b0e8f7..a135fd8 100644
--- a/lib/opendir.c
+++ b/lib/opendir.c
@@ -40,6 +40,11 @@
# include <unistd.h>
#endif
+#ifdef __KLIBC__
+# include <io.h>
+# include <fcntl.h>
+#endif
+
DIR *
opendir (const char *dir_name)
{
@@ -51,6 +56,22 @@ opendir (const char *dir_name)
if (dirp == NULL)
return NULL;
+# ifdef __KLIBC__
+ {
+ int fd = open (dir_name, O_RDONLY);
+ if (fd == -1 || _gl_register_dirp_fd (fd, dirp))
+ {
+ int saved_errno = errno;
+
+ close (fd);
+ closedir (dirp);
+
+ errno = saved_errno;
+
+ return NULL;
+ }
+ }
+# endif
#else
char dir_name_mask[MAX_PATH + 1 + 1 + 1];
diff --git a/m4/closedir.m4 b/m4/closedir.m4
index dab6673..4be0ebd 100644
--- a/m4/closedir.m4
+++ b/m4/closedir.m4
@@ -1,4 +1,4 @@
-# closedir.m4 serial 2
+# closedir.m4 serial 3
dnl Copyright (C) 2011-2016 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -22,4 +22,11 @@ AC_DEFUN([gl_FUNC_CLOSEDIR],
fi
fi
])
+ dnl Replace closedir() on OS/2 kLIBC for support dirfd() function replaced
+ dnl by gnulib.
+ if test -z "${host_os##os2*}"; then
+ if test $HAVE_OPENDIR = 1; then
+ REPLACE_OPENDIR=1
+ fi
+ fi
])
diff --git a/m4/dirfd.m4 b/m4/dirfd.m4
index e9532e6..8195b78 100644
--- a/m4/dirfd.m4
+++ b/m4/dirfd.m4
@@ -1,4 +1,4 @@
-# serial 22 -*- Autoconf -*-
+# serial 23 -*- Autoconf -*-
dnl Find out how to get the file descriptor associated with an open DIR*.
@@ -35,11 +35,15 @@ AC_DEFUN([gl_FUNC_DIRFD],
gl_cv_func_dirfd_macro=yes,
gl_cv_func_dirfd_macro=no)])
- # Use the replacement only if we have no function or macro with that name.
- if test $ac_cv_func_dirfd = no && test $gl_cv_func_dirfd_macro = no; then
+ # Use the replacement if we have no function or macro with that name,
+ # or if OS/2 kLIBC whose dirfd() does not work.
+ if test $ac_cv_func_dirfd = no && test $gl_cv_func_dirfd_macro = no \
+ || test -z "${host_os##os2*}" ; then
if test $ac_cv_have_decl_dirfd = yes; then
# If the system declares dirfd already, let's declare rpl_dirfd instead.
REPLACE_DIRFD=1
+ AC_DEFINE([REPLACE_DIRFD], [1],
+ [Define to 1 if gnulib's dirfd() replacement is used.])
fi
fi
])
diff --git a/m4/opendir.m4 b/m4/opendir.m4
index 1181dde..2124f98 100644
--- a/m4/opendir.m4
+++ b/m4/opendir.m4
@@ -1,4 +1,4 @@
-# opendir.m4 serial 2
+# opendir.m4 serial 3
dnl Copyright (C) 2011-2016 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -22,4 +22,11 @@ AC_DEFUN([gl_FUNC_OPENDIR],
fi
fi
])
+ dnl Replace opendir() on OS/2 kLIBC to support dirfd() function replaced
+ dnl by gnulib.
+ if test -z "${host_os##os2*}"; then
+ if test $HAVE_OPENDIR = 1; then
+ REPLACE_OPENDIR=1
+ fi
+ fi
])
diff --git a/modules/closedir b/modules/closedir
index 8fb9645..0763878 100644
--- a/modules/closedir
+++ b/modules/closedir
@@ -8,6 +8,7 @@ m4/closedir.m4
Depends-on:
dirent
+dirfd [test $HAVE_CLOSEDIR = 0 || test $REPLACE_CLOSEDIR = 1]
configure.ac:
gl_FUNC_CLOSEDIR
diff --git a/modules/dirfd b/modules/dirfd
index 1c6d26f..0ad0bf4 100644
--- a/modules/dirfd
+++ b/modules/dirfd
@@ -8,11 +8,12 @@ m4/dirfd.m4
Depends-on:
dirent
extensions
-errno [test $ac_cv_func_dirfd = no && test $gl_cv_func_dirfd_macro = no]
+errno [test $ac_cv_func_dirfd = no && test $gl_cv_func_dirfd_macro = no || test $REPLACE_DIRFD = 1]
configure.ac:
gl_FUNC_DIRFD
-if test $ac_cv_func_dirfd = no && test $gl_cv_func_dirfd_macro = no; then
+if test $ac_cv_func_dirfd = no && test $gl_cv_func_dirfd_macro = no \
+ || test $REPLACE_DIRFD = 1; then
AC_LIBOBJ([dirfd])
gl_PREREQ_DIRFD
fi
diff --git a/modules/opendir b/modules/opendir
index cfb9e1a..8192853 100644
--- a/modules/opendir
+++ b/modules/opendir
@@ -12,6 +12,7 @@ largefile
filename [test $HAVE_OPENDIR = 0 || test $REPLACE_OPENDIR = 1]
unistd [test $HAVE_OPENDIR = 0 || test $REPLACE_OPENDIR = 1]
closedir [test $HAVE_OPENDIR = 0 || test $REPLACE_OPENDIR = 1]
+dirfd [test $HAVE_OPENDIR = 0 || test $REPLACE_OPENDIR = 1]
configure.ac:
gl_FUNC_OPENDIR
--
2.7.0