From 2ed40ad9975efd1452ec9a0960f11719b0dd30f4 Mon Sep 17 00:00:00 2001 From: KO Myung-Hun Date: Sun, 7 Dec 2014 17:03:42 +0900 Subject: [PATCH] dup, dup2, fcntl: support a directory fd on OS/2 kLIBC On OS/2 kLIBC, dup(), dup2() and fcntl() do not work on a directory fd. * lib/dup.c (dup_nothrow): New. * lib/dup2.c (klibc_dup2dirfd): New. dup2() for a directory fd. (klibc_dup2): New. * lib/fcntl.c (klibc_fcntl): New. * m4/dup.m4 (gl_FUNC_DUP): Check if dup() works on a directory fd. * m4/dup2.m4 (gl_FUNC_DUP2): Check if dup2() works on a directory fd. * m4/fcntl.m4 (gl_FUNC_FCNTL): Check if F_DUPFD works on a directory fd. --- lib/dup.c | 25 ++++++++++++++++++ lib/dup2.c | 51 ++++++++++++++++++++++++++++++++++++ lib/fcntl.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ m4/dup.m4 | 30 ++++++++++++++++++++- m4/dup2.m4 | 15 ++++++++++- m4/fcntl.m4 | 14 +++++++++- 6 files changed, 219 insertions(+), 3 deletions(-) diff --git a/lib/dup.c b/lib/dup.c index c813df6..a2e43ec 100644 --- a/lib/dup.c +++ b/lib/dup.c @@ -45,6 +45,31 @@ dup_nothrow (int fd) return result; } +#elif defined __KLIBC__ +# include +# include + +# include + +static int +dup_nothrow (int fd) +{ + int dupfd; + struct stat sbuf; + + dupfd = dup (fd); + if (dupfd == -1 && errno == ENOTSUP \ + && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode)) + { + char path[_MAX_PATH]; + + /* Get a path from fd */ + if (!__libc_Back_ioFHToPath (fd, path, sizeof (path))) + dupfd = open (path, O_RDONLY); + } + + return dupfd; +} #else # define dup_nothrow dup #endif diff --git a/lib/dup2.c b/lib/dup2.c index 7de6805..a1fff0a 100644 --- a/lib/dup2.c +++ b/lib/dup2.c @@ -85,6 +85,57 @@ ms_windows_dup2 (int fd, int desired_fd) # define dup2 ms_windows_dup2 +# elif defined __KLIBC__ + +# include + +static int +klibc_dup2dirfd (int fd, int desired_fd) +{ + int tempfd; + int dupfd; + + tempfd = open ("NUL", O_RDONLY); + if (tempfd == -1) + return -1; + + if (tempfd == desired_fd) + { + close (tempfd); + + char path[_MAX_PATH]; + if (__libc_Back_ioFHToPath (fd, path, sizeof (path))) + return -1; + + return open(path, O_RDONLY); + } + + dupfd = klibc_dup2dirfd (fd, desired_fd); + + close (tempfd); + + return dupfd; +} + +static int +klibc_dup2 (int fd, int desired_fd) +{ + int dupfd; + struct stat sbuf; + + dupfd = dup2 (fd, desired_fd); + if (dupfd == -1 && errno == ENOTSUP \ + && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode)) + { + close (desired_fd); + + return klibc_dup2dirfd (fd, desired_fd); + } + + return dupfd; +} + +# define dup2 klibc_dup2 # endif int diff --git a/lib/fcntl.c b/lib/fcntl.c index 1e35dd1..1f88b95 100644 --- a/lib/fcntl.c +++ b/lib/fcntl.c @@ -162,6 +162,93 @@ dupfd (int oldfd, int newfd, int flags) } #endif /* W32 */ +#ifdef __KLIBC__ + +# define INCL_DOS +# include + +static int +klibc_fcntl (int fd, int action, /* arg */...) +{ + va_list arg_ptr; + int arg; + struct stat sbuf; + int result = -1; + + va_start (arg_ptr, action); + arg = va_arg (arg_ptr, int); + result = fcntl (fd, action, arg); + /* EPERM for F_DUPFD, ENOTSUP for others */ + if (result == -1 && (errno == EPERM || errno == ENOTSUP) \ + && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode)) + { + ULONG ulMode; + + switch (action) + { + case F_DUPFD: + /* Find available fd */ + while (fcntl (arg, F_GETFL) != -1 || errno != EBADF) + arg++; + + result = dup2 (fd, arg); + break; + + /* Using underlying APIs is right ? */ + case F_GETFD: + if (DosQueryFHState (fd, &ulMode)) + break; + + result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0; + break; + + case F_SETFD: + if (arg & ~FD_CLOEXEC) + break; + + if (DosQueryFHState (fd, &ulMode)) + break; + + if (arg & FD_CLOEXEC) + ulMode |= OPEN_FLAGS_NOINHERIT; + else + ulMode &= ~OPEN_FLAGS_NOINHERIT; + + /* Filter supported flags. */ + ulMode &= OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR \ + | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT; + + if (DosSetFHState (fd, ulMode)) + break; + + result = 0; + break; + + case F_GETFL: + result = 0; + break; + + case F_SETFL: + if (arg != 0) + break; + + result = 0; + break; + + default : + errno = EINVAL; + break; + } + } + + va_end (arg_ptr); + + return result; +} + +# define fcntl klibc_fcntl +#endif + /* Perform the specified ACTION on the file descriptor FD, possibly using the argument ARG further described below. This replacement handles the following actions, and forwards all others on to the diff --git a/m4/dup.m4 b/m4/dup.m4 index 9393bc5..03ee089 100644 --- a/m4/dup.m4 +++ b/m4/dup.m4 @@ -1,4 +1,4 @@ -# dup.m4 serial 3 +# dup.m4 serial 4 dnl Copyright (C) 2011-2014 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -19,6 +19,34 @@ AC_DEFUN([gl_FUNC_DUP], REPLACE_DUP=1 fi ]) + AC_CACHE_CHECK([whether dup works], [gl_cv_func_dup_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[#include +#include +#include ]], + [int result = 0; + int fd; + + /* On OS/2 kLIBC, dup() does not work on a directory fd. */ + fd = open (".", O_RDONLY); + if (fd == -1) + result |= 1; + else if (dup (fd) == -1 ) + result |= 2; + + close (fd); + + return result; + ]) + ], + [gl_cv_func_dup_works=yes], [gl_cv_func_dup_works=no]) + ]) + case "$gl_cv_func_dup_works" in + *yes) ;; + *) + REPLACE_DUP=1 + ;; + esac ]) # Prerequisites of lib/dup.c. diff --git a/m4/dup2.m4 b/m4/dup2.m4 index 6498fc2..a9b1873 100644 --- a/m4/dup2.m4 +++ b/m4/dup2.m4 @@ -1,4 +1,4 @@ -#serial 20 +#serial 21 dnl Copyright (C) 2002, 2005, 2007, 2009-2014 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -50,6 +50,17 @@ AC_DEFUN([gl_FUNC_DUP2], result |= 32; dup2 (2, 255); dup2 (2, 256); + /* On OS/2 kLIBC, dup2() does not work on a directory fd. */ + { + int fd = open (".", O_RDONLY); + if (fd == -1) + result |= 64; + else if (dup2 (fd, fd + 1) == -1 ) + result |= 128; + + close (fd); + } + return result; ]) ], @@ -68,6 +79,8 @@ AC_DEFUN([gl_FUNC_DUP2], gl_cv_func_dup2_works="guessing no" ;; haiku*) # on Haiku alpha 2, dup2(1, 1) resets FD_CLOEXEC. gl_cv_func_dup2_works="guessing no" ;; + os2*) # on OS/2 kLIBC, dup2() does not work on a directory fd. + gl_cv_func_dup2_works="guessing no" ;; *) gl_cv_func_dup2_works="guessing yes" ;; esac]) ]) diff --git a/m4/fcntl.m4 b/m4/fcntl.m4 index f824beb..009c520 100644 --- a/m4/fcntl.m4 +++ b/m4/fcntl.m4 @@ -1,4 +1,4 @@ -# fcntl.m4 serial 5 +# fcntl.m4 serial 6 dnl Copyright (C) 2009-2014 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -43,6 +43,18 @@ AC_DEFUN([gl_FUNC_FCNTL], if (errno != EINVAL) result |= 2; if (fcntl (0, F_DUPFD, bad_fd) != -1) result |= 4; if (errno != EINVAL) result |= 8; + /* On OS/2 kLIBC, F_DUPFD does not work on a directory fd */ + { + int fd; + fd = open (".", O_RDONLY); + if (fd == -1) + result |= 16; + else if (fcntl (fd, F_DUPFD, STDERR_FILENO + 1) == -1) + result |= 32; + + close (fd); + } + return result; ]])], [gl_cv_func_fcntl_f_dupfd_works=yes], -- 1.8.5.2