##// END OF EJS Templates
win32: work around a WinError problem handling HRESULT types...
Matt Harbison -
r33419:7c33adc8 default
parent child Browse files
Show More
@@ -1,458 +1,463 b''
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_OUTPUT_HANDLE = _DWORD(-11).value
135 _STD_ERROR_HANDLE = _DWORD(-12).value
135 _STD_ERROR_HANDLE = _DWORD(-12).value
136
136
137 # types of parameters of C functions used (required by pypy)
137 # types of parameters of C functions used (required by pypy)
138
138
139 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
139 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
140 _DWORD, _DWORD, _HANDLE]
140 _DWORD, _DWORD, _HANDLE]
141 _kernel32.CreateFileA.restype = _HANDLE
141 _kernel32.CreateFileA.restype = _HANDLE
142
142
143 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
143 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
144 _kernel32.GetFileInformationByHandle.restype = _BOOL
144 _kernel32.GetFileInformationByHandle.restype = _BOOL
145
145
146 _kernel32.CloseHandle.argtypes = [_HANDLE]
146 _kernel32.CloseHandle.argtypes = [_HANDLE]
147 _kernel32.CloseHandle.restype = _BOOL
147 _kernel32.CloseHandle.restype = _BOOL
148
148
149 try:
149 try:
150 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
150 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
151 _kernel32.CreateHardLinkA.restype = _BOOL
151 _kernel32.CreateHardLinkA.restype = _BOOL
152 except AttributeError:
152 except AttributeError:
153 pass
153 pass
154
154
155 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
155 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
156 _kernel32.SetFileAttributesA.restype = _BOOL
156 _kernel32.SetFileAttributesA.restype = _BOOL
157
157
158 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
158 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
159 _kernel32.OpenProcess.restype = _HANDLE
159 _kernel32.OpenProcess.restype = _HANDLE
160
160
161 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
161 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
162 _kernel32.GetExitCodeProcess.restype = _BOOL
162 _kernel32.GetExitCodeProcess.restype = _BOOL
163
163
164 _kernel32.GetLastError.argtypes = []
164 _kernel32.GetLastError.argtypes = []
165 _kernel32.GetLastError.restype = _DWORD
165 _kernel32.GetLastError.restype = _DWORD
166
166
167 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
167 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
168 _kernel32.GetModuleFileNameA.restype = _DWORD
168 _kernel32.GetModuleFileNameA.restype = _DWORD
169
169
170 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
170 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
171 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
171 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
172 ctypes.c_void_p]
172 ctypes.c_void_p]
173 _kernel32.CreateProcessA.restype = _BOOL
173 _kernel32.CreateProcessA.restype = _BOOL
174
174
175 _kernel32.ExitProcess.argtypes = [_UINT]
175 _kernel32.ExitProcess.argtypes = [_UINT]
176 _kernel32.ExitProcess.restype = None
176 _kernel32.ExitProcess.restype = None
177
177
178 _kernel32.GetCurrentProcessId.argtypes = []
178 _kernel32.GetCurrentProcessId.argtypes = []
179 _kernel32.GetCurrentProcessId.restype = _DWORD
179 _kernel32.GetCurrentProcessId.restype = _DWORD
180
180
181 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
181 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
182 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
182 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
183 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
183 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
184
184
185 _kernel32.SetConsoleMode.argtypes = [_HANDLE, _DWORD]
185 _kernel32.SetConsoleMode.argtypes = [_HANDLE, _DWORD]
186 _kernel32.SetConsoleMode.restype = _BOOL
186 _kernel32.SetConsoleMode.restype = _BOOL
187
187
188 _kernel32.GetConsoleMode.argtypes = [_HANDLE, ctypes.c_void_p]
188 _kernel32.GetConsoleMode.argtypes = [_HANDLE, ctypes.c_void_p]
189 _kernel32.GetConsoleMode.restype = _BOOL
189 _kernel32.GetConsoleMode.restype = _BOOL
190
190
191 _kernel32.GetStdHandle.argtypes = [_DWORD]
191 _kernel32.GetStdHandle.argtypes = [_DWORD]
192 _kernel32.GetStdHandle.restype = _HANDLE
192 _kernel32.GetStdHandle.restype = _HANDLE
193
193
194 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
194 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
195 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
195 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
196
196
197 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
197 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
198 _advapi32.GetUserNameA.restype = _BOOL
198 _advapi32.GetUserNameA.restype = _BOOL
199
199
200 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
200 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
201 _user32.GetWindowThreadProcessId.restype = _DWORD
201 _user32.GetWindowThreadProcessId.restype = _DWORD
202
202
203 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
203 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
204 _user32.ShowWindow.restype = _BOOL
204 _user32.ShowWindow.restype = _BOOL
205
205
206 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
206 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
207 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
207 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
208 _user32.EnumWindows.restype = _BOOL
208 _user32.EnumWindows.restype = _BOOL
209
209
210 _kernel32.PeekNamedPipe.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD,
210 _kernel32.PeekNamedPipe.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD,
211 ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
211 ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
212 _kernel32.PeekNamedPipe.restype = _BOOL
212 _kernel32.PeekNamedPipe.restype = _BOOL
213
213
214 def _raiseoserror(name):
214 def _raiseoserror(name):
215 err = ctypes.WinError()
215 # Force the code to a signed int to avoid an 'int too large' error.
216 # See https://bugs.python.org/issue28474
217 code = _kernel32.GetLastError()
218 if code > 0x7fffffff:
219 code -= 2**32
220 err = ctypes.WinError(code=code)
216 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
221 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
217
222
218 def _getfileinfo(name):
223 def _getfileinfo(name):
219 fh = _kernel32.CreateFileA(name, 0,
224 fh = _kernel32.CreateFileA(name, 0,
220 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
225 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
221 None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
226 None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
222 if fh == _INVALID_HANDLE_VALUE:
227 if fh == _INVALID_HANDLE_VALUE:
223 _raiseoserror(name)
228 _raiseoserror(name)
224 try:
229 try:
225 fi = _BY_HANDLE_FILE_INFORMATION()
230 fi = _BY_HANDLE_FILE_INFORMATION()
226 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
231 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
227 _raiseoserror(name)
232 _raiseoserror(name)
228 return fi
233 return fi
229 finally:
234 finally:
230 _kernel32.CloseHandle(fh)
235 _kernel32.CloseHandle(fh)
231
236
232 def oslink(src, dst):
237 def oslink(src, dst):
233 try:
238 try:
234 if not _kernel32.CreateHardLinkA(dst, src, None):
239 if not _kernel32.CreateHardLinkA(dst, src, None):
235 _raiseoserror(src)
240 _raiseoserror(src)
236 except AttributeError: # Wine doesn't support this function
241 except AttributeError: # Wine doesn't support this function
237 _raiseoserror(src)
242 _raiseoserror(src)
238
243
239 def nlinks(name):
244 def nlinks(name):
240 '''return number of hardlinks for the given file'''
245 '''return number of hardlinks for the given file'''
241 return _getfileinfo(name).nNumberOfLinks
246 return _getfileinfo(name).nNumberOfLinks
242
247
243 def samefile(path1, path2):
248 def samefile(path1, path2):
244 '''Returns whether path1 and path2 refer to the same file or directory.'''
249 '''Returns whether path1 and path2 refer to the same file or directory.'''
245 res1 = _getfileinfo(path1)
250 res1 = _getfileinfo(path1)
246 res2 = _getfileinfo(path2)
251 res2 = _getfileinfo(path2)
247 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
252 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
248 and res1.nFileIndexHigh == res2.nFileIndexHigh
253 and res1.nFileIndexHigh == res2.nFileIndexHigh
249 and res1.nFileIndexLow == res2.nFileIndexLow)
254 and res1.nFileIndexLow == res2.nFileIndexLow)
250
255
251 def samedevice(path1, path2):
256 def samedevice(path1, path2):
252 '''Returns whether path1 and path2 are on the same device.'''
257 '''Returns whether path1 and path2 are on the same device.'''
253 res1 = _getfileinfo(path1)
258 res1 = _getfileinfo(path1)
254 res2 = _getfileinfo(path2)
259 res2 = _getfileinfo(path2)
255 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
260 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
256
261
257 def peekpipe(pipe):
262 def peekpipe(pipe):
258 handle = msvcrt.get_osfhandle(pipe.fileno())
263 handle = msvcrt.get_osfhandle(pipe.fileno())
259 avail = _DWORD()
264 avail = _DWORD()
260
265
261 if not _kernel32.PeekNamedPipe(handle, None, 0, None, ctypes.byref(avail),
266 if not _kernel32.PeekNamedPipe(handle, None, 0, None, ctypes.byref(avail),
262 None):
267 None):
263 err = _kernel32.GetLastError()
268 err = _kernel32.GetLastError()
264 if err == _ERROR_BROKEN_PIPE:
269 if err == _ERROR_BROKEN_PIPE:
265 return 0
270 return 0
266 raise ctypes.WinError(err)
271 raise ctypes.WinError(err)
267
272
268 return avail.value
273 return avail.value
269
274
270 def testpid(pid):
275 def testpid(pid):
271 '''return True if pid is still running or unable to
276 '''return True if pid is still running or unable to
272 determine, False otherwise'''
277 determine, False otherwise'''
273 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
278 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
274 if h:
279 if h:
275 try:
280 try:
276 status = _DWORD()
281 status = _DWORD()
277 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
282 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
278 return status.value == _STILL_ACTIVE
283 return status.value == _STILL_ACTIVE
279 finally:
284 finally:
280 _kernel32.CloseHandle(h)
285 _kernel32.CloseHandle(h)
281 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
286 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
282
287
283 def executablepath():
288 def executablepath():
284 '''return full path of hg.exe'''
289 '''return full path of hg.exe'''
285 size = 600
290 size = 600
286 buf = ctypes.create_string_buffer(size + 1)
291 buf = ctypes.create_string_buffer(size + 1)
287 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
292 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
288 if len == 0:
293 if len == 0:
289 raise ctypes.WinError() # Note: WinError is a function
294 raise ctypes.WinError() # Note: WinError is a function
290 elif len == size:
295 elif len == size:
291 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
296 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
292 return buf.value
297 return buf.value
293
298
294 def getuser():
299 def getuser():
295 '''return name of current user'''
300 '''return name of current user'''
296 size = _DWORD(300)
301 size = _DWORD(300)
297 buf = ctypes.create_string_buffer(size.value + 1)
302 buf = ctypes.create_string_buffer(size.value + 1)
298 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
303 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
299 raise ctypes.WinError()
304 raise ctypes.WinError()
300 return buf.value
305 return buf.value
301
306
302 _signalhandler = []
307 _signalhandler = []
303
308
304 def setsignalhandler():
309 def setsignalhandler():
305 '''Register a termination handler for console events including
310 '''Register a termination handler for console events including
306 CTRL+C. python signal handlers do not work well with socket
311 CTRL+C. python signal handlers do not work well with socket
307 operations.
312 operations.
308 '''
313 '''
309 def handler(event):
314 def handler(event):
310 _kernel32.ExitProcess(1)
315 _kernel32.ExitProcess(1)
311
316
312 if _signalhandler:
317 if _signalhandler:
313 return # already registered
318 return # already registered
314 h = _SIGNAL_HANDLER(handler)
319 h = _SIGNAL_HANDLER(handler)
315 _signalhandler.append(h) # needed to prevent garbage collection
320 _signalhandler.append(h) # needed to prevent garbage collection
316 if not _kernel32.SetConsoleCtrlHandler(h, True):
321 if not _kernel32.SetConsoleCtrlHandler(h, True):
317 raise ctypes.WinError()
322 raise ctypes.WinError()
318
323
319 def hidewindow():
324 def hidewindow():
320
325
321 def callback(hwnd, pid):
326 def callback(hwnd, pid):
322 wpid = _DWORD()
327 wpid = _DWORD()
323 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
328 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
324 if pid == wpid.value:
329 if pid == wpid.value:
325 _user32.ShowWindow(hwnd, _SW_HIDE)
330 _user32.ShowWindow(hwnd, _SW_HIDE)
326 return False # stop enumerating windows
331 return False # stop enumerating windows
327 return True
332 return True
328
333
329 pid = _kernel32.GetCurrentProcessId()
334 pid = _kernel32.GetCurrentProcessId()
330 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
335 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
331
336
332 def termsize():
337 def termsize():
333 # cmd.exe does not handle CR like a unix console, the CR is
338 # cmd.exe does not handle CR like a unix console, the CR is
334 # counted in the line length. On 80 columns consoles, if 80
339 # counted in the line length. On 80 columns consoles, if 80
335 # characters are written, the following CR won't apply on the
340 # characters are written, the following CR won't apply on the
336 # current line but on the new one. Keep room for it.
341 # current line but on the new one. Keep room for it.
337 width = 80 - 1
342 width = 80 - 1
338 height = 25
343 height = 25
339 # Query stderr to avoid problems with redirections
344 # Query stderr to avoid problems with redirections
340 screenbuf = _kernel32.GetStdHandle(
345 screenbuf = _kernel32.GetStdHandle(
341 _STD_ERROR_HANDLE) # don't close the handle returned
346 _STD_ERROR_HANDLE) # don't close the handle returned
342 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
347 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
343 return width, height
348 return width, height
344 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
349 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
345 if not _kernel32.GetConsoleScreenBufferInfo(
350 if not _kernel32.GetConsoleScreenBufferInfo(
346 screenbuf, ctypes.byref(csbi)):
351 screenbuf, ctypes.byref(csbi)):
347 return width, height
352 return width, height
348 width = csbi.srWindow.Right - csbi.srWindow.Left # don't '+ 1'
353 width = csbi.srWindow.Right - csbi.srWindow.Left # don't '+ 1'
349 height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1
354 height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1
350 return width, height
355 return width, height
351
356
352 def enablevtmode():
357 def enablevtmode():
353 '''Enable virtual terminal mode for the associated console. Return True if
358 '''Enable virtual terminal mode for the associated console. Return True if
354 enabled, else False.'''
359 enabled, else False.'''
355
360
356 ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4
361 ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4
357
362
358 handle = _kernel32.GetStdHandle(_STD_OUTPUT_HANDLE) # don't close the handle
363 handle = _kernel32.GetStdHandle(_STD_OUTPUT_HANDLE) # don't close the handle
359 if handle == _INVALID_HANDLE_VALUE:
364 if handle == _INVALID_HANDLE_VALUE:
360 return False
365 return False
361
366
362 mode = _DWORD(0)
367 mode = _DWORD(0)
363
368
364 if not _kernel32.GetConsoleMode(handle, ctypes.byref(mode)):
369 if not _kernel32.GetConsoleMode(handle, ctypes.byref(mode)):
365 return False
370 return False
366
371
367 if (mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0:
372 if (mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0:
368 mode.value |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
373 mode.value |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
369
374
370 if not _kernel32.SetConsoleMode(handle, mode):
375 if not _kernel32.SetConsoleMode(handle, mode):
371 return False
376 return False
372
377
373 return True
378 return True
374
379
375 def spawndetached(args):
380 def spawndetached(args):
376 # No standard library function really spawns a fully detached
381 # No standard library function really spawns a fully detached
377 # process under win32 because they allocate pipes or other objects
382 # process under win32 because they allocate pipes or other objects
378 # to handle standard streams communications. Passing these objects
383 # to handle standard streams communications. Passing these objects
379 # to the child process requires handle inheritance to be enabled
384 # to the child process requires handle inheritance to be enabled
380 # which makes really detached processes impossible.
385 # which makes really detached processes impossible.
381 si = _STARTUPINFO()
386 si = _STARTUPINFO()
382 si.cb = ctypes.sizeof(_STARTUPINFO)
387 si.cb = ctypes.sizeof(_STARTUPINFO)
383
388
384 pi = _PROCESS_INFORMATION()
389 pi = _PROCESS_INFORMATION()
385
390
386 env = ''
391 env = ''
387 for k in encoding.environ:
392 for k in encoding.environ:
388 env += "%s=%s\0" % (k, encoding.environ[k])
393 env += "%s=%s\0" % (k, encoding.environ[k])
389 if not env:
394 if not env:
390 env = '\0'
395 env = '\0'
391 env += '\0'
396 env += '\0'
392
397
393 args = subprocess.list2cmdline(args)
398 args = subprocess.list2cmdline(args)
394
399
395 res = _kernel32.CreateProcessA(
400 res = _kernel32.CreateProcessA(
396 None, args, None, None, False, _CREATE_NO_WINDOW,
401 None, args, None, None, False, _CREATE_NO_WINDOW,
397 env, pycompat.getcwd(), ctypes.byref(si), ctypes.byref(pi))
402 env, pycompat.getcwd(), ctypes.byref(si), ctypes.byref(pi))
398 if not res:
403 if not res:
399 raise ctypes.WinError()
404 raise ctypes.WinError()
400
405
401 return pi.dwProcessId
406 return pi.dwProcessId
402
407
403 def unlink(f):
408 def unlink(f):
404 '''try to implement POSIX' unlink semantics on Windows'''
409 '''try to implement POSIX' unlink semantics on Windows'''
405
410
406 if os.path.isdir(f):
411 if os.path.isdir(f):
407 # use EPERM because it is POSIX prescribed value, even though
412 # use EPERM because it is POSIX prescribed value, even though
408 # unlink(2) on directories returns EISDIR on Linux
413 # unlink(2) on directories returns EISDIR on Linux
409 raise IOError(errno.EPERM,
414 raise IOError(errno.EPERM,
410 "Unlinking directory not permitted: '%s'" % f)
415 "Unlinking directory not permitted: '%s'" % f)
411
416
412 # POSIX allows to unlink and rename open files. Windows has serious
417 # POSIX allows to unlink and rename open files. Windows has serious
413 # problems with doing that:
418 # problems with doing that:
414 # - Calling os.unlink (or os.rename) on a file f fails if f or any
419 # - Calling os.unlink (or os.rename) on a file f fails if f or any
415 # hardlinked copy of f has been opened with Python's open(). There is no
420 # hardlinked copy of f has been opened with Python's open(). There is no
416 # way such a file can be deleted or renamed on Windows (other than
421 # way such a file can be deleted or renamed on Windows (other than
417 # scheduling the delete or rename for the next reboot).
422 # scheduling the delete or rename for the next reboot).
418 # - Calling os.unlink on a file that has been opened with Mercurial's
423 # - Calling os.unlink on a file that has been opened with Mercurial's
419 # posixfile (or comparable methods) will delay the actual deletion of
424 # posixfile (or comparable methods) will delay the actual deletion of
420 # the file for as long as the file is held open. The filename is blocked
425 # the file for as long as the file is held open. The filename is blocked
421 # during that time and cannot be used for recreating a new file under
426 # during that time and cannot be used for recreating a new file under
422 # that same name ("zombie file"). Directories containing such zombie files
427 # that same name ("zombie file"). Directories containing such zombie files
423 # cannot be removed or moved.
428 # cannot be removed or moved.
424 # A file that has been opened with posixfile can be renamed, so we rename
429 # A file that has been opened with posixfile can be renamed, so we rename
425 # f to a random temporary name before calling os.unlink on it. This allows
430 # f to a random temporary name before calling os.unlink on it. This allows
426 # callers to recreate f immediately while having other readers do their
431 # callers to recreate f immediately while having other readers do their
427 # implicit zombie filename blocking on a temporary name.
432 # implicit zombie filename blocking on a temporary name.
428
433
429 for tries in xrange(10):
434 for tries in xrange(10):
430 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
435 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
431 try:
436 try:
432 os.rename(f, temp) # raises OSError EEXIST if temp exists
437 os.rename(f, temp) # raises OSError EEXIST if temp exists
433 break
438 break
434 except OSError as e:
439 except OSError as e:
435 if e.errno != errno.EEXIST:
440 if e.errno != errno.EEXIST:
436 raise
441 raise
437 else:
442 else:
438 raise IOError(errno.EEXIST, "No usable temporary filename found")
443 raise IOError(errno.EEXIST, "No usable temporary filename found")
439
444
440 try:
445 try:
441 os.unlink(temp)
446 os.unlink(temp)
442 except OSError:
447 except OSError:
443 # The unlink might have failed because the READONLY attribute may heave
448 # The unlink might have failed because the READONLY attribute may heave
444 # been set on the original file. Rename works fine with READONLY set,
449 # been set on the original file. Rename works fine with READONLY set,
445 # but not os.unlink. Reset all attributes and try again.
450 # but not os.unlink. Reset all attributes and try again.
446 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
451 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
447 try:
452 try:
448 os.unlink(temp)
453 os.unlink(temp)
449 except OSError:
454 except OSError:
450 # The unlink might have failed due to some very rude AV-Scanners.
455 # The unlink might have failed due to some very rude AV-Scanners.
451 # Leaking a tempfile is the lesser evil than aborting here and
456 # Leaking a tempfile is the lesser evil than aborting here and
452 # leaving some potentially serious inconsistencies.
457 # leaving some potentially serious inconsistencies.
453 pass
458 pass
454
459
455 def makedir(path, notindexed):
460 def makedir(path, notindexed):
456 os.mkdir(path)
461 os.mkdir(path)
457 if notindexed:
462 if notindexed:
458 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
463 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
General Comments 0
You need to be logged in to leave comments. Login now