utimens: cache whether utimensat syscall works
[pspp] / lib / dup3.c
index b9fb341f3b3fe94df45233ef6a0fee21b6a9d8cc..879a9074f2cfbf53626ddc3839db7f1a5eaf093a 100644 (file)
@@ -29,6 +29,8 @@
 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 /* Native Woe32 API.  */
 
+# include <string.h>
+
 /* Get declarations of the Win32 API functions.  */
 # define WIN32_LEAN_AND_MEAN
 # include <windows.h>
 int
 dup3 (int oldfd, int newfd, int flags)
 {
+#if HAVE_DUP3
+# undef dup3
+  /* Try the system call first, if it exists.  (We may be running with a glibc
+     that has the function but with an older kernel that lacks it.)  */
+  {
+    /* Cache the information whether the system call really exists.  */
+    static int have_dup3_really; /* 0 = unknown, 1 = yes, -1 = no */
+    if (have_dup3_really >= 0)
+      {
+       int result = dup3 (oldfd, newfd, flags);
+       if (!(result < 0 && errno == ENOSYS))
+         {
+           have_dup3_really = 1;
+#if REPLACE_FCHDIR
+           if (0 <= result)
+             result = _gl_register_dup (oldfd, newfd);
+#endif
+           return result;
+         }
+       have_dup3_really = -1;
+      }
+  }
+#endif
+
   if (oldfd < 0 || newfd < 0 || newfd >= getdtablesize ())
     {
       errno = EBADF;
@@ -158,6 +184,10 @@ dup3 (int oldfd, int newfd, int flags)
        errno = saved_errno;
       }
 
+#if REPLACE_FCHDIR
+      if (result == newfd)
+       result = _gl_register_dup (oldfd, newfd);
+#endif
       return result;
     }
 
@@ -196,5 +226,8 @@ dup3 (int oldfd, int newfd, int flags)
     setmode (newfd, O_TEXT);
 #endif
 
+#if REPLACE_FCHDIR
+  newfd = _gl_register_dup (oldfd, newfd);
+#endif
   return newfd;
 }