Before, isatty() was an alias for WinAPI _isatty().
This resulted in wrong result for mintty.

Implement a pipe name check in a static isatty().
This makes io.h include NT and Windows APIs.

The change isn't strictly standard, as it adds
'static' to the isatty() signature.

Signed-off-by: Mihail Konev <k....@ya.ru>
Moved-from: https://github.com/Alexpux/mingw-w64/pull/3
Reference: https://cygwin.com/ml/cygwin-developers/2016-11/msg00002.html
---
v4:
- do not check for msys-* pipe name
- fix typos

This would only work for MSYS once it is patched to revert pipe names.

 mingw-w64-headers/crt/io.h | 105 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 104 insertions(+), 1 deletion(-)

diff --git a/mingw-w64-headers/crt/io.h b/mingw-w64-headers/crt/io.h
index c61e94ab8743..9fa776c8c9b1 100644
--- a/mingw-w64-headers/crt/io.h
+++ b/mingw-w64-headers/crt/io.h
@@ -9,6 +9,12 @@
 #include <crtdefs.h>
 #include <string.h>
 
+/* for cygwin-compatible isatty */
+#include <wchar.h>
+#include <errno.h>
+#include <winternl.h>
+#include <windows.h>
+
 #pragma pack(push,_CRT_PACKING)
 
 #ifdef __cplusplus
@@ -322,7 +328,6 @@ _CRTIMP char* __cdecl _getcwd (char*, int);
   int __cdecl dup2(int _FileHandleSrc,int _FileHandleDst) 
__MINGW_ATTRIB_DEPRECATED_MSVC2005;
   int __cdecl eof(int _FileHandle) __MINGW_ATTRIB_DEPRECATED_MSVC2005;
   long __cdecl filelength(int _FileHandle) __MINGW_ATTRIB_DEPRECATED_MSVC2005;
-  int __cdecl isatty(int _FileHandle) __MINGW_ATTRIB_DEPRECATED_MSVC2005;
   int __cdecl locking(int _FileHandle,int _LockMode,long _NumOfBytes) 
__MINGW_ATTRIB_DEPRECATED_MSVC2005;
   long __cdecl lseek(int _FileHandle,long _Offset,int _Origin) 
__MINGW_ATTRIB_DEPRECATED_MSVC2005;
   char *__cdecl mktemp(char *_TemplateName)  
__MINGW_ATTRIB_DEPRECATED_MSVC2005;
@@ -335,6 +340,104 @@ _CRTIMP char* __cdecl _getcwd (char*, int);
   int __cdecl write(int _Filehandle,const void *_Buf,unsigned int 
_MaxCharCount) __MINGW_ATTRIB_DEPRECATED_MSVC2005;
 #endif
 
+/* Cygwin-compatible isatty.
+ *
+ * Cygwin pty is a specially-named named pipe.
+ * Fetch [absolute] fd's NT object path (if any),
+ * and check it for the following pattern:
+ *
+ *   
\Device\NamedPipe\cygwin-[a-fA-F0-9]{16}-pty[0-9]{1,4}-(from-master|to-master|to-master-cyg)
+ *
+ * [a-fA-F0-9] is the cygwin installation key, 16 characters long.
+ * pty[0-9] is the pty name. Its index is of type int, but is safe to be 
limited to 4 characters.
+ *
+ * */
+
+static int __cdecl isatty(int fd) {
+  wchar_t const expect_dev[] = L"\\Device\\NamedPipe\\cygwin-";
+  wchar_t const expect_pty[] = L"-pty";
+
+  typedef NTSTATUS (NTAPI proc_NtQueryObject) (HANDLE, 
OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG);
+  proc_NtQueryObject *pNtQueryObject;
+
+  HANDLE h_fd;
+
+  /* NtQueryObject needs space for OBJECT_NAME_INFORMATION.Name->Buffer also. 
*/
+  char ntfn_bytes[sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
+
+  OBJECT_NAME_INFORMATION *ntfn = (OBJECT_NAME_INFORMATION*) ntfn_bytes;
+  NTSTATUS status;
+  ULONG ntfn_size = sizeof(ntfn_bytes);
+
+  wchar_t c, *s;
+  int l;
+
+  h_fd = (HANDLE) _get_osfhandle(fd);
+  if (!h_fd || h_fd == INVALID_HANDLE_VALUE) {
+    errno = EBADF;
+    return 0;
+  }
+
+  pNtQueryObject = (proc_NtQueryObject*) 
GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryObject");
+  if (!pNtQueryObject) {
+    goto no_tty;
+  }
+
+  memset(ntfn, 0, ntfn_size);
+  status = pNtQueryObject((HANDLE)h_fd, ObjectNameInformation,
+      ntfn, ntfn_size, &ntfn_size);
+
+  if (!NT_SUCCESS(status)) {
+    /* If it is not NUL (i.e. \Device\Null, which would succeed),
+     * then normal isatty() could be consulted.
+     * */
+    if (_isatty(fd)) {
+      return 1;
+    }
+    goto no_tty;
+  }
+
+  s = ntfn->Name.Buffer;
+  s[ntfn->Name.Length / sizeof(WCHAR)] = 0;
+
+  l = wcslen(expect_dev);
+  if (wcsncmp(s, expect_dev, l) != 0) {
+    goto no_tty;
+  }
+  s += l;
+
+  l = wcsspn(s, L"0123456789abcdefABCDEF");
+  if (l != 16) {
+    goto no_tty;
+  }
+  s += l;
+
+  l = wcslen(expect_pty);
+  if (wcsncmp(s, expect_pty, l) != 0) {
+    goto no_tty;
+  }
+  s += l;
+
+  l = wcsspn(s, L"0123456789");
+  if (l < 1 || l > 4) {
+    goto no_tty;
+  }
+  s += l;
+
+  if (wcscmp(s, L"-from-master") != 0 &&
+        wcscmp(s, L"-to-master") != 0 &&
+        wcscmp(s, L"-to-master-cyg") != 0)
+  {
+    goto no_tty;
+  }
+
+  return 1;
+
+no_tty:
+  errno = EINVAL;
+  return 0;
+}
+
 #ifndef _FILE_OFFSET_BITS_SET_LSEEK
 #define _FILE_OFFSET_BITS_SET_LSEEK
 #if (defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64))
-- 
2.9.2


------------------------------------------------------------------------------
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to