podman

Форк
0
/
isatty_windows.go 
125 строк · 3.3 Кб
1
//go:build windows && !appengine
2
// +build windows,!appengine
3

4
package isatty
5

6
import (
7
	"errors"
8
	"strings"
9
	"syscall"
10
	"unicode/utf16"
11
	"unsafe"
12
)
13

14
const (
15
	objectNameInfo uintptr = 1
16
	fileNameInfo           = 2
17
	fileTypePipe           = 3
18
)
19

20
var (
21
	kernel32                         = syscall.NewLazyDLL("kernel32.dll")
22
	ntdll                            = syscall.NewLazyDLL("ntdll.dll")
23
	procGetConsoleMode               = kernel32.NewProc("GetConsoleMode")
24
	procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
25
	procGetFileType                  = kernel32.NewProc("GetFileType")
26
	procNtQueryObject                = ntdll.NewProc("NtQueryObject")
27
)
28

29
func init() {
30
	// Check if GetFileInformationByHandleEx is available.
31
	if procGetFileInformationByHandleEx.Find() != nil {
32
		procGetFileInformationByHandleEx = nil
33
	}
34
}
35

36
// IsTerminal return true if the file descriptor is terminal.
37
func IsTerminal(fd uintptr) bool {
38
	var st uint32
39
	r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
40
	return r != 0 && e == 0
41
}
42

43
// Check pipe name is used for cygwin/msys2 pty.
44
// Cygwin/MSYS2 PTY has a name like:
45
//   \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
46
func isCygwinPipeName(name string) bool {
47
	token := strings.Split(name, "-")
48
	if len(token) < 5 {
49
		return false
50
	}
51

52
	if token[0] != `\msys` &&
53
		token[0] != `\cygwin` &&
54
		token[0] != `\Device\NamedPipe\msys` &&
55
		token[0] != `\Device\NamedPipe\cygwin` {
56
		return false
57
	}
58

59
	if token[1] == "" {
60
		return false
61
	}
62

63
	if !strings.HasPrefix(token[2], "pty") {
64
		return false
65
	}
66

67
	if token[3] != `from` && token[3] != `to` {
68
		return false
69
	}
70

71
	if token[4] != "master" {
72
		return false
73
	}
74

75
	return true
76
}
77

78
// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler
79
// since GetFileInformationByHandleEx is not available under windows Vista and still some old fashion
80
// guys are using Windows XP, this is a workaround for those guys, it will also work on system from
81
// Windows vista to 10
82
// see https://stackoverflow.com/a/18792477 for details
83
func getFileNameByHandle(fd uintptr) (string, error) {
84
	if procNtQueryObject == nil {
85
		return "", errors.New("ntdll.dll: NtQueryObject not supported")
86
	}
87

88
	var buf [4 + syscall.MAX_PATH]uint16
89
	var result int
90
	r, _, e := syscall.Syscall6(procNtQueryObject.Addr(), 5,
91
		fd, objectNameInfo, uintptr(unsafe.Pointer(&buf)), uintptr(2*len(buf)), uintptr(unsafe.Pointer(&result)), 0)
92
	if r != 0 {
93
		return "", e
94
	}
95
	return string(utf16.Decode(buf[4 : 4+buf[0]/2])), nil
96
}
97

98
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
99
// terminal.
100
func IsCygwinTerminal(fd uintptr) bool {
101
	if procGetFileInformationByHandleEx == nil {
102
		name, err := getFileNameByHandle(fd)
103
		if err != nil {
104
			return false
105
		}
106
		return isCygwinPipeName(name)
107
	}
108

109
	// Cygwin/msys's pty is a pipe.
110
	ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
111
	if ft != fileTypePipe || e != 0 {
112
		return false
113
	}
114

115
	var buf [2 + syscall.MAX_PATH]uint16
116
	r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
117
		4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
118
		uintptr(len(buf)*2), 0, 0)
119
	if r == 0 || e != 0 {
120
		return false
121
	}
122

123
	l := *(*uint32)(unsafe.Pointer(&buf))
124
	return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
125
}
126

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.