bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v7 07/11] dup, dup2, fcntl: support a directory fd on OS/2 kLIBC


From: KO Myung-Hun
Subject: [PATCH v7 07/11] dup, dup2, fcntl: support a directory fd on OS/2 kLIBC
Date: Thu, 14 Jan 2016 11:23:47 +0900

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  | 14 +++++++++-
 m4/fcntl.m4 | 13 ++++++++-
 6 files changed, 217 insertions(+), 3 deletions(-)

diff --git a/lib/dup.c b/lib/dup.c
index f1fa5f9..1f488f2 100644
--- a/lib/dup.c
+++ b/lib/dup.c
@@ -45,6 +45,31 @@ dup_nothrow (int fd)
 
   return result;
 }
+#elif defined __KLIBC__
+# include <fcntl.h>
+# include <sys/stat.h>
+
+# include <InnoTekLIBC/backend.h>
+
+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 c913f47..5d026f2 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 <InnoTekLIBC/backend.h>
+
+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 1ccc5ac..b7b4313 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 <os2.h>
+
+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 4fb0d30..490d921 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-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,
@@ -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 <unistd.h>
+#include <fcntl.h>
+#include <errno.h>]],
+         [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 63d6d8e..5b68312 100644
--- a/m4/dup2.m4
+++ b/m4/dup2.m4
@@ -1,4 +1,4 @@
-#serial 24
+#serial 25
 dnl Copyright (C) 2002, 2005, 2007, 2009-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,
@@ -62,6 +62,16 @@ 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;]])
         ],
         [gl_cv_func_dup2_works=yes], [gl_cv_func_dup2_works=no],
@@ -78,6 +88,8 @@ AC_DEFUN([gl_FUNC_DUP2],
              gl_cv_func_dup2_works="guessing no" ;;
            *-android*) # implemented using dup3(), which fails if oldfd == 
newfd
              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 0037e5f..bb61470 100644
--- a/m4/fcntl.m4
+++ b/m4/fcntl.m4
@@ -1,4 +1,4 @@
-# fcntl.m4 serial 8
+# fcntl.m4 serial 9
 dnl Copyright (C) 2009-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,
@@ -54,6 +54,17 @@ 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],
          [gl_cv_func_fcntl_f_dupfd_works=no],
-- 
2.7.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]