##// END OF EJS Templates
win32: add a method to enable ANSI color code processing on Windows 10...
Matt Harbison -
r32664:2d56e6d2 default
parent child Browse files
Show More
@@ -1,508 +1,538
1 # win32.py - utility functions that use win32 API
1 # win32.py - utility functions that use win32 API
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import ctypes
10 import ctypes
11 import errno
11 import errno
12 import msvcrt
12 import msvcrt
13 import os
13 import os
14 import random
14 import random
15 import subprocess
15 import subprocess
16
16
17 from . import (
17 from . import (
18 encoding,
18 encoding,
19 pycompat,
19 pycompat,
20 )
20 )
21
21
22 _kernel32 = ctypes.windll.kernel32
22 _kernel32 = ctypes.windll.kernel32
23 _advapi32 = ctypes.windll.advapi32
23 _advapi32 = ctypes.windll.advapi32
24 _user32 = ctypes.windll.user32
24 _user32 = ctypes.windll.user32
25
25
26 _BOOL = ctypes.c_long
26 _BOOL = ctypes.c_long
27 _WORD = ctypes.c_ushort
27 _WORD = ctypes.c_ushort
28 _DWORD = ctypes.c_ulong
28 _DWORD = ctypes.c_ulong
29 _UINT = ctypes.c_uint
29 _UINT = ctypes.c_uint
30 _LONG = ctypes.c_long
30 _LONG = ctypes.c_long
31 _LPCSTR = _LPSTR = ctypes.c_char_p
31 _LPCSTR = _LPSTR = ctypes.c_char_p
32 _HANDLE = ctypes.c_void_p
32 _HANDLE = ctypes.c_void_p
33 _HWND = _HANDLE
33 _HWND = _HANDLE
34
34
35 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
35 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
36
36
37 # GetLastError
37 # GetLastError
38 _ERROR_SUCCESS = 0
38 _ERROR_SUCCESS = 0
39 _ERROR_NO_MORE_FILES = 18
39 _ERROR_NO_MORE_FILES = 18
40 _ERROR_INVALID_PARAMETER = 87
40 _ERROR_INVALID_PARAMETER = 87
41 _ERROR_BROKEN_PIPE = 109
41 _ERROR_BROKEN_PIPE = 109
42 _ERROR_INSUFFICIENT_BUFFER = 122
42 _ERROR_INSUFFICIENT_BUFFER = 122
43
43
44 # WPARAM is defined as UINT_PTR (unsigned type)
44 # WPARAM is defined as UINT_PTR (unsigned type)
45 # LPARAM is defined as LONG_PTR (signed type)
45 # LPARAM is defined as LONG_PTR (signed type)
46 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
46 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
47 _WPARAM = ctypes.c_ulong
47 _WPARAM = ctypes.c_ulong
48 _LPARAM = ctypes.c_long
48 _LPARAM = ctypes.c_long
49 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
49 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
50 _WPARAM = ctypes.c_ulonglong
50 _WPARAM = ctypes.c_ulonglong
51 _LPARAM = ctypes.c_longlong
51 _LPARAM = ctypes.c_longlong
52
52
53 class _FILETIME(ctypes.Structure):
53 class _FILETIME(ctypes.Structure):
54 _fields_ = [('dwLowDateTime', _DWORD),
54 _fields_ = [('dwLowDateTime', _DWORD),
55 ('dwHighDateTime', _DWORD)]
55 ('dwHighDateTime', _DWORD)]
56
56
57 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
57 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
58 _fields_ = [('dwFileAttributes', _DWORD),
58 _fields_ = [('dwFileAttributes', _DWORD),
59 ('ftCreationTime', _FILETIME),
59 ('ftCreationTime', _FILETIME),
60 ('ftLastAccessTime', _FILETIME),
60 ('ftLastAccessTime', _FILETIME),
61 ('ftLastWriteTime', _FILETIME),
61 ('ftLastWriteTime', _FILETIME),
62 ('dwVolumeSerialNumber', _DWORD),
62 ('dwVolumeSerialNumber', _DWORD),
63 ('nFileSizeHigh', _DWORD),
63 ('nFileSizeHigh', _DWORD),
64 ('nFileSizeLow', _DWORD),
64 ('nFileSizeLow', _DWORD),
65 ('nNumberOfLinks', _DWORD),
65 ('nNumberOfLinks', _DWORD),
66 ('nFileIndexHigh', _DWORD),
66 ('nFileIndexHigh', _DWORD),
67 ('nFileIndexLow', _DWORD)]
67 ('nFileIndexLow', _DWORD)]
68
68
69 # CreateFile
69 # CreateFile
70 _FILE_SHARE_READ = 0x00000001
70 _FILE_SHARE_READ = 0x00000001
71 _FILE_SHARE_WRITE = 0x00000002
71 _FILE_SHARE_WRITE = 0x00000002
72 _FILE_SHARE_DELETE = 0x00000004
72 _FILE_SHARE_DELETE = 0x00000004
73
73
74 _OPEN_EXISTING = 3
74 _OPEN_EXISTING = 3
75
75
76 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
76 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
77
77
78 # SetFileAttributes
78 # SetFileAttributes
79 _FILE_ATTRIBUTE_NORMAL = 0x80
79 _FILE_ATTRIBUTE_NORMAL = 0x80
80 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
80 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
81
81
82 # Process Security and Access Rights
82 # Process Security and Access Rights
83 _PROCESS_QUERY_INFORMATION = 0x0400
83 _PROCESS_QUERY_INFORMATION = 0x0400
84
84
85 # GetExitCodeProcess
85 # GetExitCodeProcess
86 _STILL_ACTIVE = 259
86 _STILL_ACTIVE = 259
87
87
88 class _STARTUPINFO(ctypes.Structure):
88 class _STARTUPINFO(ctypes.Structure):
89 _fields_ = [('cb', _DWORD),
89 _fields_ = [('cb', _DWORD),
90 ('lpReserved', _LPSTR),
90 ('lpReserved', _LPSTR),
91 ('lpDesktop', _LPSTR),
91 ('lpDesktop', _LPSTR),
92 ('lpTitle', _LPSTR),
92 ('lpTitle', _LPSTR),
93 ('dwX', _DWORD),
93 ('dwX', _DWORD),
94 ('dwY', _DWORD),
94 ('dwY', _DWORD),
95 ('dwXSize', _DWORD),
95 ('dwXSize', _DWORD),
96 ('dwYSize', _DWORD),
96 ('dwYSize', _DWORD),
97 ('dwXCountChars', _DWORD),
97 ('dwXCountChars', _DWORD),
98 ('dwYCountChars', _DWORD),
98 ('dwYCountChars', _DWORD),
99 ('dwFillAttribute', _DWORD),
99 ('dwFillAttribute', _DWORD),
100 ('dwFlags', _DWORD),
100 ('dwFlags', _DWORD),
101 ('wShowWindow', _WORD),
101 ('wShowWindow', _WORD),
102 ('cbReserved2', _WORD),
102 ('cbReserved2', _WORD),
103 ('lpReserved2', ctypes.c_char_p),
103 ('lpReserved2', ctypes.c_char_p),
104 ('hStdInput', _HANDLE),
104 ('hStdInput', _HANDLE),
105 ('hStdOutput', _HANDLE),
105 ('hStdOutput', _HANDLE),
106 ('hStdError', _HANDLE)]
106 ('hStdError', _HANDLE)]
107
107
108 class _PROCESS_INFORMATION(ctypes.Structure):
108 class _PROCESS_INFORMATION(ctypes.Structure):
109 _fields_ = [('hProcess', _HANDLE),
109 _fields_ = [('hProcess', _HANDLE),
110 ('hThread', _HANDLE),
110 ('hThread', _HANDLE),
111 ('dwProcessId', _DWORD),
111 ('dwProcessId', _DWORD),
112 ('dwThreadId', _DWORD)]
112 ('dwThreadId', _DWORD)]
113
113
114 _CREATE_NO_WINDOW = 0x08000000
114 _CREATE_NO_WINDOW = 0x08000000
115 _SW_HIDE = 0
115 _SW_HIDE = 0
116
116
117 class _COORD(ctypes.Structure):
117 class _COORD(ctypes.Structure):
118 _fields_ = [('X', ctypes.c_short),
118 _fields_ = [('X', ctypes.c_short),
119 ('Y', ctypes.c_short)]
119 ('Y', ctypes.c_short)]
120
120
121 class _SMALL_RECT(ctypes.Structure):
121 class _SMALL_RECT(ctypes.Structure):
122 _fields_ = [('Left', ctypes.c_short),
122 _fields_ = [('Left', ctypes.c_short),
123 ('Top', ctypes.c_short),
123 ('Top', ctypes.c_short),
124 ('Right', ctypes.c_short),
124 ('Right', ctypes.c_short),
125 ('Bottom', ctypes.c_short)]
125 ('Bottom', ctypes.c_short)]
126
126
127 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
127 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
128 _fields_ = [('dwSize', _COORD),
128 _fields_ = [('dwSize', _COORD),
129 ('dwCursorPosition', _COORD),
129 ('dwCursorPosition', _COORD),
130 ('wAttributes', _WORD),
130 ('wAttributes', _WORD),
131 ('srWindow', _SMALL_RECT),
131 ('srWindow', _SMALL_RECT),
132 ('dwMaximumWindowSize', _COORD)]
132 ('dwMaximumWindowSize', _COORD)]
133
133
134 _STD_OUTPUT_HANDLE = _DWORD(-11).value
134 _STD_ERROR_HANDLE = _DWORD(-12).value
135 _STD_ERROR_HANDLE = _DWORD(-12).value
135
136
136 # CreateToolhelp32Snapshot, Process32First, Process32Next
137 # CreateToolhelp32Snapshot, Process32First, Process32Next
137 _TH32CS_SNAPPROCESS = 0x00000002
138 _TH32CS_SNAPPROCESS = 0x00000002
138 _MAX_PATH = 260
139 _MAX_PATH = 260
139
140
140 class _tagPROCESSENTRY32(ctypes.Structure):
141 class _tagPROCESSENTRY32(ctypes.Structure):
141 _fields_ = [('dwsize', _DWORD),
142 _fields_ = [('dwsize', _DWORD),
142 ('cntUsage', _DWORD),
143 ('cntUsage', _DWORD),
143 ('th32ProcessID', _DWORD),
144 ('th32ProcessID', _DWORD),
144 ('th32DefaultHeapID', ctypes.c_void_p),
145 ('th32DefaultHeapID', ctypes.c_void_p),
145 ('th32ModuleID', _DWORD),
146 ('th32ModuleID', _DWORD),
146 ('cntThreads', _DWORD),
147 ('cntThreads', _DWORD),
147 ('th32ParentProcessID', _DWORD),
148 ('th32ParentProcessID', _DWORD),
148 ('pcPriClassBase', _LONG),
149 ('pcPriClassBase', _LONG),
149 ('dwFlags', _DWORD),
150 ('dwFlags', _DWORD),
150 ('szExeFile', ctypes.c_char * _MAX_PATH)]
151 ('szExeFile', ctypes.c_char * _MAX_PATH)]
151
152
152 def __init__(self):
153 def __init__(self):
153 super(_tagPROCESSENTRY32, self).__init__()
154 super(_tagPROCESSENTRY32, self).__init__()
154 self.dwsize = ctypes.sizeof(self)
155 self.dwsize = ctypes.sizeof(self)
155
156
156
157
157 # types of parameters of C functions used (required by pypy)
158 # types of parameters of C functions used (required by pypy)
158
159
159 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
160 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
160 _DWORD, _DWORD, _HANDLE]
161 _DWORD, _DWORD, _HANDLE]
161 _kernel32.CreateFileA.restype = _HANDLE
162 _kernel32.CreateFileA.restype = _HANDLE
162
163
163 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
164 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
164 _kernel32.GetFileInformationByHandle.restype = _BOOL
165 _kernel32.GetFileInformationByHandle.restype = _BOOL
165
166
166 _kernel32.CloseHandle.argtypes = [_HANDLE]
167 _kernel32.CloseHandle.argtypes = [_HANDLE]
167 _kernel32.CloseHandle.restype = _BOOL
168 _kernel32.CloseHandle.restype = _BOOL
168
169
169 try:
170 try:
170 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
171 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
171 _kernel32.CreateHardLinkA.restype = _BOOL
172 _kernel32.CreateHardLinkA.restype = _BOOL
172 except AttributeError:
173 except AttributeError:
173 pass
174 pass
174
175
175 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
176 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
176 _kernel32.SetFileAttributesA.restype = _BOOL
177 _kernel32.SetFileAttributesA.restype = _BOOL
177
178
178 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
179 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
179 _kernel32.OpenProcess.restype = _HANDLE
180 _kernel32.OpenProcess.restype = _HANDLE
180
181
181 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
182 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
182 _kernel32.GetExitCodeProcess.restype = _BOOL
183 _kernel32.GetExitCodeProcess.restype = _BOOL
183
184
184 _kernel32.GetLastError.argtypes = []
185 _kernel32.GetLastError.argtypes = []
185 _kernel32.GetLastError.restype = _DWORD
186 _kernel32.GetLastError.restype = _DWORD
186
187
187 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
188 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
188 _kernel32.GetModuleFileNameA.restype = _DWORD
189 _kernel32.GetModuleFileNameA.restype = _DWORD
189
190
190 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
191 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
191 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
192 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
192 ctypes.c_void_p]
193 ctypes.c_void_p]
193 _kernel32.CreateProcessA.restype = _BOOL
194 _kernel32.CreateProcessA.restype = _BOOL
194
195
195 _kernel32.ExitProcess.argtypes = [_UINT]
196 _kernel32.ExitProcess.argtypes = [_UINT]
196 _kernel32.ExitProcess.restype = None
197 _kernel32.ExitProcess.restype = None
197
198
198 _kernel32.GetCurrentProcessId.argtypes = []
199 _kernel32.GetCurrentProcessId.argtypes = []
199 _kernel32.GetCurrentProcessId.restype = _DWORD
200 _kernel32.GetCurrentProcessId.restype = _DWORD
200
201
201 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
202 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
202 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
203 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
203 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
204 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
204
205
206 _kernel32.SetConsoleMode.argtypes = [_HANDLE, _DWORD]
207 _kernel32.SetConsoleMode.restype = _BOOL
208
209 _kernel32.GetConsoleMode.argtypes = [_HANDLE, ctypes.c_void_p]
210 _kernel32.GetConsoleMode.restype = _BOOL
211
205 _kernel32.GetStdHandle.argtypes = [_DWORD]
212 _kernel32.GetStdHandle.argtypes = [_DWORD]
206 _kernel32.GetStdHandle.restype = _HANDLE
213 _kernel32.GetStdHandle.restype = _HANDLE
207
214
208 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
215 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
209 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
216 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
210
217
211 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
218 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
212 _advapi32.GetUserNameA.restype = _BOOL
219 _advapi32.GetUserNameA.restype = _BOOL
213
220
214 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
221 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
215 _user32.GetWindowThreadProcessId.restype = _DWORD
222 _user32.GetWindowThreadProcessId.restype = _DWORD
216
223
217 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
224 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
218 _user32.ShowWindow.restype = _BOOL
225 _user32.ShowWindow.restype = _BOOL
219
226
220 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
227 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
221 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
228 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
222 _user32.EnumWindows.restype = _BOOL
229 _user32.EnumWindows.restype = _BOOL
223
230
224 _kernel32.CreateToolhelp32Snapshot.argtypes = [_DWORD, _DWORD]
231 _kernel32.CreateToolhelp32Snapshot.argtypes = [_DWORD, _DWORD]
225 _kernel32.CreateToolhelp32Snapshot.restype = _BOOL
232 _kernel32.CreateToolhelp32Snapshot.restype = _BOOL
226
233
227 _kernel32.PeekNamedPipe.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD,
234 _kernel32.PeekNamedPipe.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD,
228 ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
235 ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
229 _kernel32.PeekNamedPipe.restype = _BOOL
236 _kernel32.PeekNamedPipe.restype = _BOOL
230
237
231 _kernel32.Process32First.argtypes = [_HANDLE, ctypes.c_void_p]
238 _kernel32.Process32First.argtypes = [_HANDLE, ctypes.c_void_p]
232 _kernel32.Process32First.restype = _BOOL
239 _kernel32.Process32First.restype = _BOOL
233
240
234 _kernel32.Process32Next.argtypes = [_HANDLE, ctypes.c_void_p]
241 _kernel32.Process32Next.argtypes = [_HANDLE, ctypes.c_void_p]
235 _kernel32.Process32Next.restype = _BOOL
242 _kernel32.Process32Next.restype = _BOOL
236
243
237 def _raiseoserror(name):
244 def _raiseoserror(name):
238 err = ctypes.WinError()
245 err = ctypes.WinError()
239 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
246 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
240
247
241 def _getfileinfo(name):
248 def _getfileinfo(name):
242 fh = _kernel32.CreateFileA(name, 0,
249 fh = _kernel32.CreateFileA(name, 0,
243 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
250 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
244 None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
251 None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
245 if fh == _INVALID_HANDLE_VALUE:
252 if fh == _INVALID_HANDLE_VALUE:
246 _raiseoserror(name)
253 _raiseoserror(name)
247 try:
254 try:
248 fi = _BY_HANDLE_FILE_INFORMATION()
255 fi = _BY_HANDLE_FILE_INFORMATION()
249 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
256 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
250 _raiseoserror(name)
257 _raiseoserror(name)
251 return fi
258 return fi
252 finally:
259 finally:
253 _kernel32.CloseHandle(fh)
260 _kernel32.CloseHandle(fh)
254
261
255 def oslink(src, dst):
262 def oslink(src, dst):
256 try:
263 try:
257 if not _kernel32.CreateHardLinkA(dst, src, None):
264 if not _kernel32.CreateHardLinkA(dst, src, None):
258 _raiseoserror(src)
265 _raiseoserror(src)
259 except AttributeError: # Wine doesn't support this function
266 except AttributeError: # Wine doesn't support this function
260 _raiseoserror(src)
267 _raiseoserror(src)
261
268
262 def nlinks(name):
269 def nlinks(name):
263 '''return number of hardlinks for the given file'''
270 '''return number of hardlinks for the given file'''
264 return _getfileinfo(name).nNumberOfLinks
271 return _getfileinfo(name).nNumberOfLinks
265
272
266 def samefile(path1, path2):
273 def samefile(path1, path2):
267 '''Returns whether path1 and path2 refer to the same file or directory.'''
274 '''Returns whether path1 and path2 refer to the same file or directory.'''
268 res1 = _getfileinfo(path1)
275 res1 = _getfileinfo(path1)
269 res2 = _getfileinfo(path2)
276 res2 = _getfileinfo(path2)
270 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
277 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
271 and res1.nFileIndexHigh == res2.nFileIndexHigh
278 and res1.nFileIndexHigh == res2.nFileIndexHigh
272 and res1.nFileIndexLow == res2.nFileIndexLow)
279 and res1.nFileIndexLow == res2.nFileIndexLow)
273
280
274 def samedevice(path1, path2):
281 def samedevice(path1, path2):
275 '''Returns whether path1 and path2 are on the same device.'''
282 '''Returns whether path1 and path2 are on the same device.'''
276 res1 = _getfileinfo(path1)
283 res1 = _getfileinfo(path1)
277 res2 = _getfileinfo(path2)
284 res2 = _getfileinfo(path2)
278 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
285 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
279
286
280 def peekpipe(pipe):
287 def peekpipe(pipe):
281 handle = msvcrt.get_osfhandle(pipe.fileno())
288 handle = msvcrt.get_osfhandle(pipe.fileno())
282 avail = _DWORD()
289 avail = _DWORD()
283
290
284 if not _kernel32.PeekNamedPipe(handle, None, 0, None, ctypes.byref(avail),
291 if not _kernel32.PeekNamedPipe(handle, None, 0, None, ctypes.byref(avail),
285 None):
292 None):
286 err = _kernel32.GetLastError()
293 err = _kernel32.GetLastError()
287 if err == _ERROR_BROKEN_PIPE:
294 if err == _ERROR_BROKEN_PIPE:
288 return 0
295 return 0
289 raise ctypes.WinError(err)
296 raise ctypes.WinError(err)
290
297
291 return avail.value
298 return avail.value
292
299
293 def testpid(pid):
300 def testpid(pid):
294 '''return True if pid is still running or unable to
301 '''return True if pid is still running or unable to
295 determine, False otherwise'''
302 determine, False otherwise'''
296 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
303 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
297 if h:
304 if h:
298 try:
305 try:
299 status = _DWORD()
306 status = _DWORD()
300 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
307 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
301 return status.value == _STILL_ACTIVE
308 return status.value == _STILL_ACTIVE
302 finally:
309 finally:
303 _kernel32.CloseHandle(h)
310 _kernel32.CloseHandle(h)
304 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
311 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
305
312
306 def executablepath():
313 def executablepath():
307 '''return full path of hg.exe'''
314 '''return full path of hg.exe'''
308 size = 600
315 size = 600
309 buf = ctypes.create_string_buffer(size + 1)
316 buf = ctypes.create_string_buffer(size + 1)
310 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
317 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
311 if len == 0:
318 if len == 0:
312 raise ctypes.WinError() # Note: WinError is a function
319 raise ctypes.WinError() # Note: WinError is a function
313 elif len == size:
320 elif len == size:
314 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
321 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
315 return buf.value
322 return buf.value
316
323
317 def getuser():
324 def getuser():
318 '''return name of current user'''
325 '''return name of current user'''
319 size = _DWORD(300)
326 size = _DWORD(300)
320 buf = ctypes.create_string_buffer(size.value + 1)
327 buf = ctypes.create_string_buffer(size.value + 1)
321 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
328 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
322 raise ctypes.WinError()
329 raise ctypes.WinError()
323 return buf.value
330 return buf.value
324
331
325 _signalhandler = []
332 _signalhandler = []
326
333
327 def setsignalhandler():
334 def setsignalhandler():
328 '''Register a termination handler for console events including
335 '''Register a termination handler for console events including
329 CTRL+C. python signal handlers do not work well with socket
336 CTRL+C. python signal handlers do not work well with socket
330 operations.
337 operations.
331 '''
338 '''
332 def handler(event):
339 def handler(event):
333 _kernel32.ExitProcess(1)
340 _kernel32.ExitProcess(1)
334
341
335 if _signalhandler:
342 if _signalhandler:
336 return # already registered
343 return # already registered
337 h = _SIGNAL_HANDLER(handler)
344 h = _SIGNAL_HANDLER(handler)
338 _signalhandler.append(h) # needed to prevent garbage collection
345 _signalhandler.append(h) # needed to prevent garbage collection
339 if not _kernel32.SetConsoleCtrlHandler(h, True):
346 if not _kernel32.SetConsoleCtrlHandler(h, True):
340 raise ctypes.WinError()
347 raise ctypes.WinError()
341
348
342 def hidewindow():
349 def hidewindow():
343
350
344 def callback(hwnd, pid):
351 def callback(hwnd, pid):
345 wpid = _DWORD()
352 wpid = _DWORD()
346 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
353 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
347 if pid == wpid.value:
354 if pid == wpid.value:
348 _user32.ShowWindow(hwnd, _SW_HIDE)
355 _user32.ShowWindow(hwnd, _SW_HIDE)
349 return False # stop enumerating windows
356 return False # stop enumerating windows
350 return True
357 return True
351
358
352 pid = _kernel32.GetCurrentProcessId()
359 pid = _kernel32.GetCurrentProcessId()
353 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
360 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
354
361
355 def termsize():
362 def termsize():
356 # cmd.exe does not handle CR like a unix console, the CR is
363 # cmd.exe does not handle CR like a unix console, the CR is
357 # counted in the line length. On 80 columns consoles, if 80
364 # counted in the line length. On 80 columns consoles, if 80
358 # characters are written, the following CR won't apply on the
365 # characters are written, the following CR won't apply on the
359 # current line but on the new one. Keep room for it.
366 # current line but on the new one. Keep room for it.
360 width = 80 - 1
367 width = 80 - 1
361 height = 25
368 height = 25
362 # Query stderr to avoid problems with redirections
369 # Query stderr to avoid problems with redirections
363 screenbuf = _kernel32.GetStdHandle(
370 screenbuf = _kernel32.GetStdHandle(
364 _STD_ERROR_HANDLE) # don't close the handle returned
371 _STD_ERROR_HANDLE) # don't close the handle returned
365 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
372 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
366 return width, height
373 return width, height
367 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
374 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
368 if not _kernel32.GetConsoleScreenBufferInfo(
375 if not _kernel32.GetConsoleScreenBufferInfo(
369 screenbuf, ctypes.byref(csbi)):
376 screenbuf, ctypes.byref(csbi)):
370 return width, height
377 return width, height
371 width = csbi.srWindow.Right - csbi.srWindow.Left # don't '+ 1'
378 width = csbi.srWindow.Right - csbi.srWindow.Left # don't '+ 1'
372 height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1
379 height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1
373 return width, height
380 return width, height
374
381
382 def enablevtmode():
383 '''Enable virtual terminal mode for the associated console. Return True if
384 enabled, else False.'''
385
386 ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4
387
388 handle = _kernel32.GetStdHandle(_STD_OUTPUT_HANDLE) # don't close the handle
389 if handle == _INVALID_HANDLE_VALUE:
390 return False
391
392 mode = _DWORD(0)
393
394 if not _kernel32.GetConsoleMode(handle, ctypes.byref(mode)):
395 return False
396
397 if (mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0:
398 mode.value |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
399
400 if not _kernel32.SetConsoleMode(handle, mode):
401 return False
402
403 return True
404
375 def _1stchild(pid):
405 def _1stchild(pid):
376 '''return the 1st found child of the given pid
406 '''return the 1st found child of the given pid
377
407
378 None is returned when no child is found'''
408 None is returned when no child is found'''
379 pe = _tagPROCESSENTRY32()
409 pe = _tagPROCESSENTRY32()
380
410
381 # create handle to list all processes
411 # create handle to list all processes
382 ph = _kernel32.CreateToolhelp32Snapshot(_TH32CS_SNAPPROCESS, 0)
412 ph = _kernel32.CreateToolhelp32Snapshot(_TH32CS_SNAPPROCESS, 0)
383 if ph == _INVALID_HANDLE_VALUE:
413 if ph == _INVALID_HANDLE_VALUE:
384 raise ctypes.WinError()
414 raise ctypes.WinError()
385 try:
415 try:
386 r = _kernel32.Process32First(ph, ctypes.byref(pe))
416 r = _kernel32.Process32First(ph, ctypes.byref(pe))
387 # loop over all processes
417 # loop over all processes
388 while r:
418 while r:
389 if pe.th32ParentProcessID == pid:
419 if pe.th32ParentProcessID == pid:
390 # return first child found
420 # return first child found
391 return pe.th32ProcessID
421 return pe.th32ProcessID
392 r = _kernel32.Process32Next(ph, ctypes.byref(pe))
422 r = _kernel32.Process32Next(ph, ctypes.byref(pe))
393 finally:
423 finally:
394 _kernel32.CloseHandle(ph)
424 _kernel32.CloseHandle(ph)
395 if _kernel32.GetLastError() != _ERROR_NO_MORE_FILES:
425 if _kernel32.GetLastError() != _ERROR_NO_MORE_FILES:
396 raise ctypes.WinError()
426 raise ctypes.WinError()
397 return None # no child found
427 return None # no child found
398
428
399 class _tochildpid(int): # pid is _DWORD, which always matches in an int
429 class _tochildpid(int): # pid is _DWORD, which always matches in an int
400 '''helper for spawndetached, returns the child pid on conversion to string
430 '''helper for spawndetached, returns the child pid on conversion to string
401
431
402 Does not resolve the child pid immediately because the child may not yet be
432 Does not resolve the child pid immediately because the child may not yet be
403 started.
433 started.
404 '''
434 '''
405 def childpid(self):
435 def childpid(self):
406 '''returns the child pid of the first found child of the process
436 '''returns the child pid of the first found child of the process
407 with this pid'''
437 with this pid'''
408 return _1stchild(self)
438 return _1stchild(self)
409 def __str__(self):
439 def __str__(self):
410 # run when the pid is written to the file
440 # run when the pid is written to the file
411 ppid = self.childpid()
441 ppid = self.childpid()
412 if ppid is None:
442 if ppid is None:
413 # race, child has exited since check
443 # race, child has exited since check
414 # fall back to this pid. Its process will also have disappeared,
444 # fall back to this pid. Its process will also have disappeared,
415 # raising the same error type later as when the child pid would
445 # raising the same error type later as when the child pid would
416 # be returned.
446 # be returned.
417 return " %d" % self
447 return " %d" % self
418 return str(ppid)
448 return str(ppid)
419
449
420 def spawndetached(args):
450 def spawndetached(args):
421 # No standard library function really spawns a fully detached
451 # No standard library function really spawns a fully detached
422 # process under win32 because they allocate pipes or other objects
452 # process under win32 because they allocate pipes or other objects
423 # to handle standard streams communications. Passing these objects
453 # to handle standard streams communications. Passing these objects
424 # to the child process requires handle inheritance to be enabled
454 # to the child process requires handle inheritance to be enabled
425 # which makes really detached processes impossible.
455 # which makes really detached processes impossible.
426 si = _STARTUPINFO()
456 si = _STARTUPINFO()
427 si.cb = ctypes.sizeof(_STARTUPINFO)
457 si.cb = ctypes.sizeof(_STARTUPINFO)
428
458
429 pi = _PROCESS_INFORMATION()
459 pi = _PROCESS_INFORMATION()
430
460
431 env = ''
461 env = ''
432 for k in encoding.environ:
462 for k in encoding.environ:
433 env += "%s=%s\0" % (k, encoding.environ[k])
463 env += "%s=%s\0" % (k, encoding.environ[k])
434 if not env:
464 if not env:
435 env = '\0'
465 env = '\0'
436 env += '\0'
466 env += '\0'
437
467
438 args = subprocess.list2cmdline(args)
468 args = subprocess.list2cmdline(args)
439 # Not running the command in shell mode makes Python 2.6 hang when
469 # Not running the command in shell mode makes Python 2.6 hang when
440 # writing to hgweb output socket.
470 # writing to hgweb output socket.
441 comspec = encoding.environ.get("COMSPEC", "cmd.exe")
471 comspec = encoding.environ.get("COMSPEC", "cmd.exe")
442 args = comspec + " /c " + args
472 args = comspec + " /c " + args
443
473
444 res = _kernel32.CreateProcessA(
474 res = _kernel32.CreateProcessA(
445 None, args, None, None, False, _CREATE_NO_WINDOW,
475 None, args, None, None, False, _CREATE_NO_WINDOW,
446 env, pycompat.getcwd(), ctypes.byref(si), ctypes.byref(pi))
476 env, pycompat.getcwd(), ctypes.byref(si), ctypes.byref(pi))
447 if not res:
477 if not res:
448 raise ctypes.WinError()
478 raise ctypes.WinError()
449
479
450 # _tochildpid because the process is the child of COMSPEC
480 # _tochildpid because the process is the child of COMSPEC
451 return _tochildpid(pi.dwProcessId)
481 return _tochildpid(pi.dwProcessId)
452
482
453 def unlink(f):
483 def unlink(f):
454 '''try to implement POSIX' unlink semantics on Windows'''
484 '''try to implement POSIX' unlink semantics on Windows'''
455
485
456 if os.path.isdir(f):
486 if os.path.isdir(f):
457 # use EPERM because it is POSIX prescribed value, even though
487 # use EPERM because it is POSIX prescribed value, even though
458 # unlink(2) on directories returns EISDIR on Linux
488 # unlink(2) on directories returns EISDIR on Linux
459 raise IOError(errno.EPERM,
489 raise IOError(errno.EPERM,
460 "Unlinking directory not permitted: '%s'" % f)
490 "Unlinking directory not permitted: '%s'" % f)
461
491
462 # POSIX allows to unlink and rename open files. Windows has serious
492 # POSIX allows to unlink and rename open files. Windows has serious
463 # problems with doing that:
493 # problems with doing that:
464 # - Calling os.unlink (or os.rename) on a file f fails if f or any
494 # - Calling os.unlink (or os.rename) on a file f fails if f or any
465 # hardlinked copy of f has been opened with Python's open(). There is no
495 # hardlinked copy of f has been opened with Python's open(). There is no
466 # way such a file can be deleted or renamed on Windows (other than
496 # way such a file can be deleted or renamed on Windows (other than
467 # scheduling the delete or rename for the next reboot).
497 # scheduling the delete or rename for the next reboot).
468 # - Calling os.unlink on a file that has been opened with Mercurial's
498 # - Calling os.unlink on a file that has been opened with Mercurial's
469 # posixfile (or comparable methods) will delay the actual deletion of
499 # posixfile (or comparable methods) will delay the actual deletion of
470 # the file for as long as the file is held open. The filename is blocked
500 # the file for as long as the file is held open. The filename is blocked
471 # during that time and cannot be used for recreating a new file under
501 # during that time and cannot be used for recreating a new file under
472 # that same name ("zombie file"). Directories containing such zombie files
502 # that same name ("zombie file"). Directories containing such zombie files
473 # cannot be removed or moved.
503 # cannot be removed or moved.
474 # A file that has been opened with posixfile can be renamed, so we rename
504 # A file that has been opened with posixfile can be renamed, so we rename
475 # f to a random temporary name before calling os.unlink on it. This allows
505 # f to a random temporary name before calling os.unlink on it. This allows
476 # callers to recreate f immediately while having other readers do their
506 # callers to recreate f immediately while having other readers do their
477 # implicit zombie filename blocking on a temporary name.
507 # implicit zombie filename blocking on a temporary name.
478
508
479 for tries in xrange(10):
509 for tries in xrange(10):
480 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
510 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
481 try:
511 try:
482 os.rename(f, temp) # raises OSError EEXIST if temp exists
512 os.rename(f, temp) # raises OSError EEXIST if temp exists
483 break
513 break
484 except OSError as e:
514 except OSError as e:
485 if e.errno != errno.EEXIST:
515 if e.errno != errno.EEXIST:
486 raise
516 raise
487 else:
517 else:
488 raise IOError(errno.EEXIST, "No usable temporary filename found")
518 raise IOError(errno.EEXIST, "No usable temporary filename found")
489
519
490 try:
520 try:
491 os.unlink(temp)
521 os.unlink(temp)
492 except OSError:
522 except OSError:
493 # The unlink might have failed because the READONLY attribute may heave
523 # The unlink might have failed because the READONLY attribute may heave
494 # been set on the original file. Rename works fine with READONLY set,
524 # been set on the original file. Rename works fine with READONLY set,
495 # but not os.unlink. Reset all attributes and try again.
525 # but not os.unlink. Reset all attributes and try again.
496 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
526 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
497 try:
527 try:
498 os.unlink(temp)
528 os.unlink(temp)
499 except OSError:
529 except OSError:
500 # The unlink might have failed due to some very rude AV-Scanners.
530 # The unlink might have failed due to some very rude AV-Scanners.
501 # Leaking a tempfile is the lesser evil than aborting here and
531 # Leaking a tempfile is the lesser evil than aborting here and
502 # leaving some potentially serious inconsistencies.
532 # leaving some potentially serious inconsistencies.
503 pass
533 pass
504
534
505 def makedir(path, notindexed):
535 def makedir(path, notindexed):
506 os.mkdir(path)
536 os.mkdir(path)
507 if notindexed:
537 if notindexed:
508 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
538 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
General Comments 0
You need to be logged in to leave comments. Login now