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
Moved-from: https://github.com/Alexpux/mingw-w64/pull/3
Reference: https://cygwin.com/ml/cygwin-developers/2016-11/msg2.html
---
v3:
- use wide strlen + const strings
- brace one-line if branches
- describe the function
mingw-w64-headers/crt/io.h | 127 -
1 file changed, 126 insertions(+), 1 deletion(-)
diff --git a/mingw-w64-headers/crt/io.h b/mingw-w64-headers/crt/io.h
index c61e94ab8743..0376a4ff596d 100644
--- a/mingw-w64-headers/crt/io.h
+++ b/mingw-w64-headers/crt/io.h
@@ -9,6 +9,13 @@
#include
#include
+/* for cygwin-compatible isatty */
+#include
+#include
+#include
+#include
+#include
+
#pragma pack(push,_CRT_PACKING)
#ifdef __cplusplus
@@ -322,7 +329,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 +341,125 @@ _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 device namespace path to fd (if any),
+ * and check it for the following pattern:
+ *
+ *
\Device\NamedPipe\(cygwin|msys)-[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\\";
+ wchar_t const expect_cyg[] = L"cygwin-";
+ wchar_t const expect_msy[] = L"msys-";
+ wchar_t const expect_pty[] = L"-pty";
+ wchar_t const expect_tmr[] = L"-to-master";
+ wchar_t const expect_fmc[] = L"-to-master-cyg";
+ wchar_t const expect_fmr[] = L"-from-master";
+
+ 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, _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;
+
+ do {
+l = wcslen(expect_cyg);
+if (wcsncmp(s, expect_cyg, l) == 0) {
+ s += l;
+ break;
+}
+
+l = wcslen(expect_msy);
+if (wcsncmp(s, expect_msy, l) == 0) {
+ s += l;
+ break;
+}
+
+goto no_tty;
+ } while (0);
+
+ 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))