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