From c51c96db07b61042f4911f91631eaf8a7f3ddcab Mon Sep 17 00:00:00 2001 From: KO Myung-Hun Date: Fri, 28 Nov 2014 16:47:12 +0900 Subject: [PATCH] opendir, closedir, dirfd, fdopendir: port to OS/2 kLIBC * 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 f80843f..c68dff3 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 154d268..d9803af 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 c91f8e5..a1a6e98 100644 --- a/lib/dirfd.c +++ b/lib/dirfd.c @@ -22,11 +22,79 @@ #include #include +#ifdef __KLIBC__ +# include +# include + +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 837a821..071cc2e 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 + +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 9f53110..93ac276 100644 --- a/lib/opendir.c +++ b/lib/opendir.c @@ -40,6 +40,11 @@ # include #endif +#ifdef __KLIBC__ +# include +# include +#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 a4403b4..3165c92 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-2015 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 ce56cff..a8d19b9 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 cd83706..c84b9d9 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-2015 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 -- 1.9.5