Subject: 26.2.90; O_PATH problem on some versions of Cygwin

From: Ken Brown <[email-masked]>
Date: Thu, 27 Jun 2019 19:28:48 +0000

Cygwin supports the O_PATH flag starting with release 3.0.0, but it is buggy 
until release 3.0.8.  (Opening a FIFO with O_PATH causes a hang.)  The attached 
patches work around this problem.  The first patch (which still has a bug number 
that needs to be filled in) uses incorrect indentation for legibility.  The 
second patch fixes the indentation.

Ken
From 8a350e90dc8d047e8372a53dd64fc178157b3f52 Mon Sep 17 00:00:00 2001
From: Ken Brown <[email-masked]>
Date: Thu, 27 Jun 2019 14:54:09 -0400
Subject: [PATCH 1/2] Avoid O_PATH on versions of Cygwin where it is buggy

* src/dired.c [O_PATH] (use_o_path): New function.
(file_attributes): Use it.  (Bug#99999)
---
 src/dired.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/src/dired.c b/src/dired.c
index 493758292b..ac83a026de 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -36,6 +36,10 @@
 #include <filemode.h>
 #include <stat-time.h>
 
+#if defined CYGWIN && defined O_PATH
+#include <sys/utsname.h>
+#endif
+
 #include "lisp.h"
 #include "systime.h"
 #include "buffer.h"
@@ -921,6 +925,21 @@ DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 2, 0,
 			  id_format);
 }
 
+/* Cygwin supports O_PATH starting with release 3.0.0, but it is buggy
+   until release 3.0.8.  */
+#ifdef O_PATH
+static bool
+use_o_path (void)
+{
+# ifdef CYGWIN
+  struct utsname name;
+  return uname (&name) >= 0 && strverscmp (name.release, "3.0.8") >= 0;
+# else
+  return true;
+# endif
+}
+#endif
+
 static Lisp_Object
 file_attributes (int fd, char const *name,
 		 Lisp_Object dirname, Lisp_Object filename,
@@ -938,6 +957,8 @@ file_attributes (int fd, char const *name,
   int err = EINVAL;
 
 #ifdef O_PATH
+ if (use_o_path ())
+ {
   int namefd = openat (fd, name, O_PATH | O_CLOEXEC | O_NOFOLLOW);
   if (namefd < 0)
     err = errno;
@@ -960,6 +981,7 @@ file_attributes (int fd, char const *name,
 	  name = "";
 	}
     }
+ }
 #endif
 
   if (err == EINVAL)
-- 
2.21.0

From cd7bbc1e088033789b2948578fc85099ed11a2f1 Mon Sep 17 00:00:00 2001
From: Ken Brown <[email-masked]>
Date: Thu, 27 Jun 2019 15:04:05 -0400
Subject: [PATCH 2/2] ; * src/dired.c (file_attributes): Fix indentation

---
 src/dired.c | 48 ++++++++++++++++++++++++------------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/src/dired.c b/src/dired.c
index ac83a026de..dfec2d89d8 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -958,30 +958,30 @@ file_attributes (int fd, char const *name,
 
 #ifdef O_PATH
  if (use_o_path ())
- {
-  int namefd = openat (fd, name, O_PATH | O_CLOEXEC | O_NOFOLLOW);
-  if (namefd < 0)
-    err = errno;
-  else
-    {
-      record_unwind_protect_int (close_file_unwind, namefd);
-      if (fstat (namefd, &s) != 0)
-	{
-	  err = errno;
-	  /* The Linux kernel before version 3.6 does not support
-	     fstat on O_PATH file descriptors.  Handle this error like
-	     missing support for O_PATH.  */
-	  if (err == EBADF)
-	    err = EINVAL;
-	}
-      else
-	{
-	  err = 0;
-	  fd = namefd;
-	  name = "";
-	}
-    }
- }
+   {
+     int namefd = openat (fd, name, O_PATH | O_CLOEXEC | O_NOFOLLOW);
+     if (namefd < 0)
+       err = errno;
+     else
+       {
+	 record_unwind_protect_int (close_file_unwind, namefd);
+	 if (fstat (namefd, &s) != 0)
+	   {
+	     err = errno;
+	     /* The Linux kernel before version 3.6 does not support
+		fstat on O_PATH file descriptors.  Handle this error like
+		missing support for O_PATH.  */
+	     if (err == EBADF)
+	       err = EINVAL;
+	   }
+	 else
+	   {
+	     err = 0;
+	     fd = namefd;
+	     name = "";
+	   }
+       }
+   }
 #endif
 
   if (err == EINVAL)
-- 
2.21.0