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