* 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.
int
closedir (DIR *dirp)
{
-# if REPLACE_FCHDIR
+# if REPLACE_FCHDIR || REPLACE_DIRFD
int fd = dirfd (dirp);
# endif
int retval;
retval = closedir (dirp);
+# ifdef __KLIBC__
+ if (!retval)
+ _gl_unregister_dirp_fd (fd);
+# endif
#else
if (dirp->current != INVALID_HANDLE_VALUE)
# 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.
#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 = 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;
}
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)
{
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
# include <unistd.h>
#endif
+#ifdef __KLIBC__
+# include <io.h>
+# include <fcntl.h>
+#endif
+
DIR *
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];
-# 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,
fi
fi
])
+ dnl Replace closedir() for supporting the gnulib-defined dirfd() function.
+ if test -z "${host_os##os2*}"; then
+ if test $HAVE_OPENDIR = 1; then
+ REPLACE_OPENDIR=1
+ fi
+ fi
])
-# serial 22 -*- Autoconf -*-
+# serial 23 -*- Autoconf -*-
dnl Find out how to get the file descriptor associated with an open DIR*.
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
])
-# 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,
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
])
Depends-on:
dirent
+dirfd [test $HAVE_CLOSEDIR = 0 || test $REPLACE_CLOSEDIR = 1]
configure.ac:
gl_FUNC_CLOSEDIR
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
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