##// END OF EJS Templates
windows: fix incorrect detection of broken pipe when writing to pager...
Sune Foldager -
r38575:3a0f322a stable
parent child Browse files
Show More
@@ -1,640 +1,647 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
48
48 # WPARAM is defined as UINT_PTR (unsigned type)
49 # WPARAM is defined as UINT_PTR (unsigned type)
49 # LPARAM is defined as LONG_PTR (signed type)
50 # LPARAM is defined as LONG_PTR (signed type)
50 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):
51 _WPARAM = ctypes.c_ulong
52 _WPARAM = ctypes.c_ulong
52 _LPARAM = ctypes.c_long
53 _LPARAM = ctypes.c_long
53 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):
54 _WPARAM = ctypes.c_ulonglong
55 _WPARAM = ctypes.c_ulonglong
55 _LPARAM = ctypes.c_longlong
56 _LPARAM = ctypes.c_longlong
56
57
57 class _FILETIME(ctypes.Structure):
58 class _FILETIME(ctypes.Structure):
58 _fields_ = [('dwLowDateTime', _DWORD),
59 _fields_ = [('dwLowDateTime', _DWORD),
59 ('dwHighDateTime', _DWORD)]
60 ('dwHighDateTime', _DWORD)]
60
61
61 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
62 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
62 _fields_ = [('dwFileAttributes', _DWORD),
63 _fields_ = [('dwFileAttributes', _DWORD),
63 ('ftCreationTime', _FILETIME),
64 ('ftCreationTime', _FILETIME),
64 ('ftLastAccessTime', _FILETIME),
65 ('ftLastAccessTime', _FILETIME),
65 ('ftLastWriteTime', _FILETIME),
66 ('ftLastWriteTime', _FILETIME),
66 ('dwVolumeSerialNumber', _DWORD),
67 ('dwVolumeSerialNumber', _DWORD),
67 ('nFileSizeHigh', _DWORD),
68 ('nFileSizeHigh', _DWORD),
68 ('nFileSizeLow', _DWORD),
69 ('nFileSizeLow', _DWORD),
69 ('nNumberOfLinks', _DWORD),
70 ('nNumberOfLinks', _DWORD),
70 ('nFileIndexHigh', _DWORD),
71 ('nFileIndexHigh', _DWORD),
71 ('nFileIndexLow', _DWORD)]
72 ('nFileIndexLow', _DWORD)]
72
73
73 # CreateFile
74 # CreateFile
74 _FILE_SHARE_READ = 0x00000001
75 _FILE_SHARE_READ = 0x00000001
75 _FILE_SHARE_WRITE = 0x00000002
76 _FILE_SHARE_WRITE = 0x00000002
76 _FILE_SHARE_DELETE = 0x00000004
77 _FILE_SHARE_DELETE = 0x00000004
77
78
78 _OPEN_EXISTING = 3
79 _OPEN_EXISTING = 3
79
80
80 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
81 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
81
82
82 # SetFileAttributes
83 # SetFileAttributes
83 _FILE_ATTRIBUTE_NORMAL = 0x80
84 _FILE_ATTRIBUTE_NORMAL = 0x80
84 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
85 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
85
86
86 # Process Security and Access Rights
87 # Process Security and Access Rights
87 _PROCESS_QUERY_INFORMATION = 0x0400
88 _PROCESS_QUERY_INFORMATION = 0x0400
88
89
89 # GetExitCodeProcess
90 # GetExitCodeProcess
90 _STILL_ACTIVE = 259
91 _STILL_ACTIVE = 259
91
92
92 class _STARTUPINFO(ctypes.Structure):
93 class _STARTUPINFO(ctypes.Structure):
93 _fields_ = [('cb', _DWORD),
94 _fields_ = [('cb', _DWORD),
94 ('lpReserved', _LPSTR),
95 ('lpReserved', _LPSTR),
95 ('lpDesktop', _LPSTR),
96 ('lpDesktop', _LPSTR),
96 ('lpTitle', _LPSTR),
97 ('lpTitle', _LPSTR),
97 ('dwX', _DWORD),
98 ('dwX', _DWORD),
98 ('dwY', _DWORD),
99 ('dwY', _DWORD),
99 ('dwXSize', _DWORD),
100 ('dwXSize', _DWORD),
100 ('dwYSize', _DWORD),
101 ('dwYSize', _DWORD),
101 ('dwXCountChars', _DWORD),
102 ('dwXCountChars', _DWORD),
102 ('dwYCountChars', _DWORD),
103 ('dwYCountChars', _DWORD),
103 ('dwFillAttribute', _DWORD),
104 ('dwFillAttribute', _DWORD),
104 ('dwFlags', _DWORD),
105 ('dwFlags', _DWORD),
105 ('wShowWindow', _WORD),
106 ('wShowWindow', _WORD),
106 ('cbReserved2', _WORD),
107 ('cbReserved2', _WORD),
107 ('lpReserved2', ctypes.c_char_p),
108 ('lpReserved2', ctypes.c_char_p),
108 ('hStdInput', _HANDLE),
109 ('hStdInput', _HANDLE),
109 ('hStdOutput', _HANDLE),
110 ('hStdOutput', _HANDLE),
110 ('hStdError', _HANDLE)]
111 ('hStdError', _HANDLE)]
111
112
112 class _PROCESS_INFORMATION(ctypes.Structure):
113 class _PROCESS_INFORMATION(ctypes.Structure):
113 _fields_ = [('hProcess', _HANDLE),
114 _fields_ = [('hProcess', _HANDLE),
114 ('hThread', _HANDLE),
115 ('hThread', _HANDLE),
115 ('dwProcessId', _DWORD),
116 ('dwProcessId', _DWORD),
116 ('dwThreadId', _DWORD)]
117 ('dwThreadId', _DWORD)]
117
118
118 _CREATE_NO_WINDOW = 0x08000000
119 _CREATE_NO_WINDOW = 0x08000000
119 _SW_HIDE = 0
120 _SW_HIDE = 0
120
121
121 class _COORD(ctypes.Structure):
122 class _COORD(ctypes.Structure):
122 _fields_ = [('X', ctypes.c_short),
123 _fields_ = [('X', ctypes.c_short),
123 ('Y', ctypes.c_short)]
124 ('Y', ctypes.c_short)]
124
125
125 class _SMALL_RECT(ctypes.Structure):
126 class _SMALL_RECT(ctypes.Structure):
126 _fields_ = [('Left', ctypes.c_short),
127 _fields_ = [('Left', ctypes.c_short),
127 ('Top', ctypes.c_short),
128 ('Top', ctypes.c_short),
128 ('Right', ctypes.c_short),
129 ('Right', ctypes.c_short),
129 ('Bottom', ctypes.c_short)]
130 ('Bottom', ctypes.c_short)]
130
131
131 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
132 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
132 _fields_ = [('dwSize', _COORD),
133 _fields_ = [('dwSize', _COORD),
133 ('dwCursorPosition', _COORD),
134 ('dwCursorPosition', _COORD),
134 ('wAttributes', _WORD),
135 ('wAttributes', _WORD),
135 ('srWindow', _SMALL_RECT),
136 ('srWindow', _SMALL_RECT),
136 ('dwMaximumWindowSize', _COORD)]
137 ('dwMaximumWindowSize', _COORD)]
137
138
138 _STD_OUTPUT_HANDLE = _DWORD(-11).value
139 _STD_OUTPUT_HANDLE = _DWORD(-11).value
139 _STD_ERROR_HANDLE = _DWORD(-12).value
140 _STD_ERROR_HANDLE = _DWORD(-12).value
140
141
141 # CERT_TRUST_STATUS dwErrorStatus
142 # CERT_TRUST_STATUS dwErrorStatus
142 CERT_TRUST_IS_PARTIAL_CHAIN = 0x10000
143 CERT_TRUST_IS_PARTIAL_CHAIN = 0x10000
143
144
144 # CertCreateCertificateContext encodings
145 # CertCreateCertificateContext encodings
145 X509_ASN_ENCODING = 0x00000001
146 X509_ASN_ENCODING = 0x00000001
146 PKCS_7_ASN_ENCODING = 0x00010000
147 PKCS_7_ASN_ENCODING = 0x00010000
147
148
148 # These structs are only complete enough to achieve what we need.
149 # These structs are only complete enough to achieve what we need.
149 class CERT_CHAIN_CONTEXT(ctypes.Structure):
150 class CERT_CHAIN_CONTEXT(ctypes.Structure):
150 _fields_ = (
151 _fields_ = (
151 ("cbSize", _DWORD),
152 ("cbSize", _DWORD),
152
153
153 # CERT_TRUST_STATUS struct
154 # CERT_TRUST_STATUS struct
154 ("dwErrorStatus", _DWORD),
155 ("dwErrorStatus", _DWORD),
155 ("dwInfoStatus", _DWORD),
156 ("dwInfoStatus", _DWORD),
156
157
157 ("cChain", _DWORD),
158 ("cChain", _DWORD),
158 ("rgpChain", ctypes.c_void_p),
159 ("rgpChain", ctypes.c_void_p),
159 ("cLowerQualityChainContext", _DWORD),
160 ("cLowerQualityChainContext", _DWORD),
160 ("rgpLowerQualityChainContext", ctypes.c_void_p),
161 ("rgpLowerQualityChainContext", ctypes.c_void_p),
161 ("fHasRevocationFreshnessTime", _BOOL),
162 ("fHasRevocationFreshnessTime", _BOOL),
162 ("dwRevocationFreshnessTime", _DWORD),
163 ("dwRevocationFreshnessTime", _DWORD),
163 )
164 )
164
165
165 class CERT_USAGE_MATCH(ctypes.Structure):
166 class CERT_USAGE_MATCH(ctypes.Structure):
166 _fields_ = (
167 _fields_ = (
167 ("dwType", _DWORD),
168 ("dwType", _DWORD),
168
169
169 # CERT_ENHKEY_USAGE struct
170 # CERT_ENHKEY_USAGE struct
170 ("cUsageIdentifier", _DWORD),
171 ("cUsageIdentifier", _DWORD),
171 ("rgpszUsageIdentifier", ctypes.c_void_p), # LPSTR *
172 ("rgpszUsageIdentifier", ctypes.c_void_p), # LPSTR *
172 )
173 )
173
174
174 class CERT_CHAIN_PARA(ctypes.Structure):
175 class CERT_CHAIN_PARA(ctypes.Structure):
175 _fields_ = (
176 _fields_ = (
176 ("cbSize", _DWORD),
177 ("cbSize", _DWORD),
177 ("RequestedUsage", CERT_USAGE_MATCH),
178 ("RequestedUsage", CERT_USAGE_MATCH),
178 ("RequestedIssuancePolicy", CERT_USAGE_MATCH),
179 ("RequestedIssuancePolicy", CERT_USAGE_MATCH),
179 ("dwUrlRetrievalTimeout", _DWORD),
180 ("dwUrlRetrievalTimeout", _DWORD),
180 ("fCheckRevocationFreshnessTime", _BOOL),
181 ("fCheckRevocationFreshnessTime", _BOOL),
181 ("dwRevocationFreshnessTime", _DWORD),
182 ("dwRevocationFreshnessTime", _DWORD),
182 ("pftCacheResync", ctypes.c_void_p), # LPFILETIME
183 ("pftCacheResync", ctypes.c_void_p), # LPFILETIME
183 ("pStrongSignPara", ctypes.c_void_p), # PCCERT_STRONG_SIGN_PARA
184 ("pStrongSignPara", ctypes.c_void_p), # PCCERT_STRONG_SIGN_PARA
184 ("dwStrongSignFlags", _DWORD),
185 ("dwStrongSignFlags", _DWORD),
185 )
186 )
186
187
187 # types of parameters of C functions used (required by pypy)
188 # types of parameters of C functions used (required by pypy)
188
189
189 _crypt32.CertCreateCertificateContext.argtypes = [_DWORD, # cert encoding
190 _crypt32.CertCreateCertificateContext.argtypes = [_DWORD, # cert encoding
190 ctypes.c_char_p, # cert
191 ctypes.c_char_p, # cert
191 _DWORD] # cert size
192 _DWORD] # cert size
192 _crypt32.CertCreateCertificateContext.restype = _PCCERT_CONTEXT
193 _crypt32.CertCreateCertificateContext.restype = _PCCERT_CONTEXT
193
194
194 _crypt32.CertGetCertificateChain.argtypes = [
195 _crypt32.CertGetCertificateChain.argtypes = [
195 ctypes.c_void_p, # HCERTCHAINENGINE
196 ctypes.c_void_p, # HCERTCHAINENGINE
196 _PCCERT_CONTEXT,
197 _PCCERT_CONTEXT,
197 ctypes.c_void_p, # LPFILETIME
198 ctypes.c_void_p, # LPFILETIME
198 ctypes.c_void_p, # HCERTSTORE
199 ctypes.c_void_p, # HCERTSTORE
199 ctypes.c_void_p, # PCERT_CHAIN_PARA
200 ctypes.c_void_p, # PCERT_CHAIN_PARA
200 _DWORD,
201 _DWORD,
201 ctypes.c_void_p, # LPVOID
202 ctypes.c_void_p, # LPVOID
202 ctypes.c_void_p # PCCERT_CHAIN_CONTEXT *
203 ctypes.c_void_p # PCCERT_CHAIN_CONTEXT *
203 ]
204 ]
204 _crypt32.CertGetCertificateChain.restype = _BOOL
205 _crypt32.CertGetCertificateChain.restype = _BOOL
205
206
206 _crypt32.CertFreeCertificateContext.argtypes = [_PCCERT_CONTEXT]
207 _crypt32.CertFreeCertificateContext.argtypes = [_PCCERT_CONTEXT]
207 _crypt32.CertFreeCertificateContext.restype = _BOOL
208 _crypt32.CertFreeCertificateContext.restype = _BOOL
208
209
209 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
210 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
210 _DWORD, _DWORD, _HANDLE]
211 _DWORD, _DWORD, _HANDLE]
211 _kernel32.CreateFileA.restype = _HANDLE
212 _kernel32.CreateFileA.restype = _HANDLE
212
213
213 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
214 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
214 _kernel32.GetFileInformationByHandle.restype = _BOOL
215 _kernel32.GetFileInformationByHandle.restype = _BOOL
215
216
216 _kernel32.CloseHandle.argtypes = [_HANDLE]
217 _kernel32.CloseHandle.argtypes = [_HANDLE]
217 _kernel32.CloseHandle.restype = _BOOL
218 _kernel32.CloseHandle.restype = _BOOL
218
219
219 try:
220 try:
220 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
221 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
221 _kernel32.CreateHardLinkA.restype = _BOOL
222 _kernel32.CreateHardLinkA.restype = _BOOL
222 except AttributeError:
223 except AttributeError:
223 pass
224 pass
224
225
225 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
226 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
226 _kernel32.SetFileAttributesA.restype = _BOOL
227 _kernel32.SetFileAttributesA.restype = _BOOL
227
228
228 _DRIVE_UNKNOWN = 0
229 _DRIVE_UNKNOWN = 0
229 _DRIVE_NO_ROOT_DIR = 1
230 _DRIVE_NO_ROOT_DIR = 1
230 _DRIVE_REMOVABLE = 2
231 _DRIVE_REMOVABLE = 2
231 _DRIVE_FIXED = 3
232 _DRIVE_FIXED = 3
232 _DRIVE_REMOTE = 4
233 _DRIVE_REMOTE = 4
233 _DRIVE_CDROM = 5
234 _DRIVE_CDROM = 5
234 _DRIVE_RAMDISK = 6
235 _DRIVE_RAMDISK = 6
235
236
236 _kernel32.GetDriveTypeA.argtypes = [_LPCSTR]
237 _kernel32.GetDriveTypeA.argtypes = [_LPCSTR]
237 _kernel32.GetDriveTypeA.restype = _UINT
238 _kernel32.GetDriveTypeA.restype = _UINT
238
239
239 _kernel32.GetVolumeInformationA.argtypes = [_LPCSTR, ctypes.c_void_p, _DWORD,
240 _kernel32.GetVolumeInformationA.argtypes = [_LPCSTR, ctypes.c_void_p, _DWORD,
240 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]
241 _kernel32.GetVolumeInformationA.restype = _BOOL
242 _kernel32.GetVolumeInformationA.restype = _BOOL
242
243
243 _kernel32.GetVolumePathNameA.argtypes = [_LPCSTR, ctypes.c_void_p, _DWORD]
244 _kernel32.GetVolumePathNameA.argtypes = [_LPCSTR, ctypes.c_void_p, _DWORD]
244 _kernel32.GetVolumePathNameA.restype = _BOOL
245 _kernel32.GetVolumePathNameA.restype = _BOOL
245
246
246 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
247 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
247 _kernel32.OpenProcess.restype = _HANDLE
248 _kernel32.OpenProcess.restype = _HANDLE
248
249
249 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
250 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
250 _kernel32.GetExitCodeProcess.restype = _BOOL
251 _kernel32.GetExitCodeProcess.restype = _BOOL
251
252
252 _kernel32.GetLastError.argtypes = []
253 _kernel32.GetLastError.argtypes = []
253 _kernel32.GetLastError.restype = _DWORD
254 _kernel32.GetLastError.restype = _DWORD
254
255
255 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
256 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
256 _kernel32.GetModuleFileNameA.restype = _DWORD
257 _kernel32.GetModuleFileNameA.restype = _DWORD
257
258
258 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
259 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
259 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,
260 ctypes.c_void_p]
261 ctypes.c_void_p]
261 _kernel32.CreateProcessA.restype = _BOOL
262 _kernel32.CreateProcessA.restype = _BOOL
262
263
263 _kernel32.ExitProcess.argtypes = [_UINT]
264 _kernel32.ExitProcess.argtypes = [_UINT]
264 _kernel32.ExitProcess.restype = None
265 _kernel32.ExitProcess.restype = None
265
266
266 _kernel32.GetCurrentProcessId.argtypes = []
267 _kernel32.GetCurrentProcessId.argtypes = []
267 _kernel32.GetCurrentProcessId.restype = _DWORD
268 _kernel32.GetCurrentProcessId.restype = _DWORD
268
269
269 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
270 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
270 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
271 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
271 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
272 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
272
273
273 _kernel32.SetConsoleMode.argtypes = [_HANDLE, _DWORD]
274 _kernel32.SetConsoleMode.argtypes = [_HANDLE, _DWORD]
274 _kernel32.SetConsoleMode.restype = _BOOL
275 _kernel32.SetConsoleMode.restype = _BOOL
275
276
276 _kernel32.GetConsoleMode.argtypes = [_HANDLE, ctypes.c_void_p]
277 _kernel32.GetConsoleMode.argtypes = [_HANDLE, ctypes.c_void_p]
277 _kernel32.GetConsoleMode.restype = _BOOL
278 _kernel32.GetConsoleMode.restype = _BOOL
278
279
279 _kernel32.GetStdHandle.argtypes = [_DWORD]
280 _kernel32.GetStdHandle.argtypes = [_DWORD]
280 _kernel32.GetStdHandle.restype = _HANDLE
281 _kernel32.GetStdHandle.restype = _HANDLE
281
282
282 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
283 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
283 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
284 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
284
285
285 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
286 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
286 _advapi32.GetUserNameA.restype = _BOOL
287 _advapi32.GetUserNameA.restype = _BOOL
287
288
288 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
289 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
289 _user32.GetWindowThreadProcessId.restype = _DWORD
290 _user32.GetWindowThreadProcessId.restype = _DWORD
290
291
291 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
292 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
292 _user32.ShowWindow.restype = _BOOL
293 _user32.ShowWindow.restype = _BOOL
293
294
294 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
295 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
295 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
296 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
296 _user32.EnumWindows.restype = _BOOL
297 _user32.EnumWindows.restype = _BOOL
297
298
298 _kernel32.PeekNamedPipe.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD,
299 _kernel32.PeekNamedPipe.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD,
299 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]
300 _kernel32.PeekNamedPipe.restype = _BOOL
301 _kernel32.PeekNamedPipe.restype = _BOOL
301
302
302 def _raiseoserror(name):
303 def _raiseoserror(name):
303 # 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.
304 # See https://bugs.python.org/issue28474
305 # See https://bugs.python.org/issue28474
305 code = _kernel32.GetLastError()
306 code = _kernel32.GetLastError()
306 if code > 0x7fffffff:
307 if code > 0x7fffffff:
307 code -= 2**32
308 code -= 2**32
308 err = ctypes.WinError(code=code)
309 err = ctypes.WinError(code=code)
309 raise OSError(err.errno, '%s: %s' % (name,
310 raise OSError(err.errno, '%s: %s' % (name,
310 encoding.strtolocal(err.strerror)))
311 encoding.strtolocal(err.strerror)))
311
312
312 def _getfileinfo(name):
313 def _getfileinfo(name):
313 fh = _kernel32.CreateFileA(name, 0,
314 fh = _kernel32.CreateFileA(name, 0,
314 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
315 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
315 None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
316 None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
316 if fh == _INVALID_HANDLE_VALUE:
317 if fh == _INVALID_HANDLE_VALUE:
317 _raiseoserror(name)
318 _raiseoserror(name)
318 try:
319 try:
319 fi = _BY_HANDLE_FILE_INFORMATION()
320 fi = _BY_HANDLE_FILE_INFORMATION()
320 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
321 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
321 _raiseoserror(name)
322 _raiseoserror(name)
322 return fi
323 return fi
323 finally:
324 finally:
324 _kernel32.CloseHandle(fh)
325 _kernel32.CloseHandle(fh)
325
326
326 def checkcertificatechain(cert, build=True):
327 def checkcertificatechain(cert, build=True):
327 '''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
328 trusted root certificate. As a side effect, missing certificates are
329 trusted root certificate. As a side effect, missing certificates are
329 downloaded and installed unless ``build=False``. True is returned if a
330 downloaded and installed unless ``build=False``. True is returned if a
330 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
331 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
332 is valid.
333 is valid.
333 '''
334 '''
334
335
335 chainctxptr = ctypes.POINTER(CERT_CHAIN_CONTEXT)
336 chainctxptr = ctypes.POINTER(CERT_CHAIN_CONTEXT)
336
337
337 pchainctx = chainctxptr()
338 pchainctx = chainctxptr()
338 chainpara = CERT_CHAIN_PARA(cbSize=ctypes.sizeof(CERT_CHAIN_PARA),
339 chainpara = CERT_CHAIN_PARA(cbSize=ctypes.sizeof(CERT_CHAIN_PARA),
339 RequestedUsage=CERT_USAGE_MATCH())
340 RequestedUsage=CERT_USAGE_MATCH())
340
341
341 certctx = _crypt32.CertCreateCertificateContext(X509_ASN_ENCODING, cert,
342 certctx = _crypt32.CertCreateCertificateContext(X509_ASN_ENCODING, cert,
342 len(cert))
343 len(cert))
343 if certctx is None:
344 if certctx is None:
344 _raiseoserror('CertCreateCertificateContext')
345 _raiseoserror('CertCreateCertificateContext')
345
346
346 flags = 0
347 flags = 0
347
348
348 if not build:
349 if not build:
349 flags |= 0x100 # CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE
350 flags |= 0x100 # CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE
350
351
351 try:
352 try:
352 # Building the certificate chain will update root certs as necessary.
353 # Building the certificate chain will update root certs as necessary.
353 if not _crypt32.CertGetCertificateChain(None, # hChainEngine
354 if not _crypt32.CertGetCertificateChain(None, # hChainEngine
354 certctx, # pCertContext
355 certctx, # pCertContext
355 None, # pTime
356 None, # pTime
356 None, # hAdditionalStore
357 None, # hAdditionalStore
357 ctypes.byref(chainpara),
358 ctypes.byref(chainpara),
358 flags,
359 flags,
359 None, # pvReserved
360 None, # pvReserved
360 ctypes.byref(pchainctx)):
361 ctypes.byref(pchainctx)):
361 _raiseoserror('CertGetCertificateChain')
362 _raiseoserror('CertGetCertificateChain')
362
363
363 chainctx = pchainctx.contents
364 chainctx = pchainctx.contents
364
365
365 return chainctx.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN == 0
366 return chainctx.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN == 0
366 finally:
367 finally:
367 if pchainctx:
368 if pchainctx:
368 _crypt32.CertFreeCertificateChain(pchainctx)
369 _crypt32.CertFreeCertificateChain(pchainctx)
369 _crypt32.CertFreeCertificateContext(certctx)
370 _crypt32.CertFreeCertificateContext(certctx)
370
371
371 def oslink(src, dst):
372 def oslink(src, dst):
372 try:
373 try:
373 if not _kernel32.CreateHardLinkA(dst, src, None):
374 if not _kernel32.CreateHardLinkA(dst, src, None):
374 _raiseoserror(src)
375 _raiseoserror(src)
375 except AttributeError: # Wine doesn't support this function
376 except AttributeError: # Wine doesn't support this function
376 _raiseoserror(src)
377 _raiseoserror(src)
377
378
378 def nlinks(name):
379 def nlinks(name):
379 '''return number of hardlinks for the given file'''
380 '''return number of hardlinks for the given file'''
380 return _getfileinfo(name).nNumberOfLinks
381 return _getfileinfo(name).nNumberOfLinks
381
382
382 def samefile(path1, path2):
383 def samefile(path1, path2):
383 '''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.'''
384 res1 = _getfileinfo(path1)
385 res1 = _getfileinfo(path1)
385 res2 = _getfileinfo(path2)
386 res2 = _getfileinfo(path2)
386 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
387 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
387 and res1.nFileIndexHigh == res2.nFileIndexHigh
388 and res1.nFileIndexHigh == res2.nFileIndexHigh
388 and res1.nFileIndexLow == res2.nFileIndexLow)
389 and res1.nFileIndexLow == res2.nFileIndexLow)
389
390
390 def samedevice(path1, path2):
391 def samedevice(path1, path2):
391 '''Returns whether path1 and path2 are on the same device.'''
392 '''Returns whether path1 and path2 are on the same device.'''
392 res1 = _getfileinfo(path1)
393 res1 = _getfileinfo(path1)
393 res2 = _getfileinfo(path2)
394 res2 = _getfileinfo(path2)
394 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
395 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
395
396
396 def peekpipe(pipe):
397 def peekpipe(pipe):
397 handle = msvcrt.get_osfhandle(pipe.fileno())
398 handle = msvcrt.get_osfhandle(pipe.fileno())
398 avail = _DWORD()
399 avail = _DWORD()
399
400
400 if not _kernel32.PeekNamedPipe(handle, None, 0, None, ctypes.byref(avail),
401 if not _kernel32.PeekNamedPipe(handle, None, 0, None, ctypes.byref(avail),
401 None):
402 None):
402 err = _kernel32.GetLastError()
403 err = _kernel32.GetLastError()
403 if err == _ERROR_BROKEN_PIPE:
404 if err == _ERROR_BROKEN_PIPE:
404 return 0
405 return 0
405 raise ctypes.WinError(err)
406 raise ctypes.WinError(err)
406
407
407 return avail.value
408 return avail.value
408
409
410 def lasterrorwaspipeerror(err):
411 if err.errno != errno.EINVAL:
412 return False
413 err = _kernel32.GetLastError()
414 return err == _ERROR_BROKEN_PIPE or err == _ERROR_NO_DATA
415
409 def testpid(pid):
416 def testpid(pid):
410 '''return True if pid is still running or unable to
417 '''return True if pid is still running or unable to
411 determine, False otherwise'''
418 determine, False otherwise'''
412 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
419 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
413 if h:
420 if h:
414 try:
421 try:
415 status = _DWORD()
422 status = _DWORD()
416 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
423 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
417 return status.value == _STILL_ACTIVE
424 return status.value == _STILL_ACTIVE
418 finally:
425 finally:
419 _kernel32.CloseHandle(h)
426 _kernel32.CloseHandle(h)
420 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
427 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
421
428
422 def executablepath():
429 def executablepath():
423 '''return full path of hg.exe'''
430 '''return full path of hg.exe'''
424 size = 600
431 size = 600
425 buf = ctypes.create_string_buffer(size + 1)
432 buf = ctypes.create_string_buffer(size + 1)
426 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
433 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
427 if len == 0:
434 if len == 0:
428 raise ctypes.WinError() # Note: WinError is a function
435 raise ctypes.WinError() # Note: WinError is a function
429 elif len == size:
436 elif len == size:
430 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
437 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
431 return buf.value
438 return buf.value
432
439
433 def getvolumename(path):
440 def getvolumename(path):
434 """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
435 (best-effort)
442 (best-effort)
436
443
437 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.
438 """
445 """
439 # realpath() calls GetFullPathName()
446 # realpath() calls GetFullPathName()
440 realpath = os.path.realpath(path)
447 realpath = os.path.realpath(path)
441
448
442 # allocate at least MAX_PATH long since GetVolumePathName('c:\\', buf, 4)
449 # allocate at least MAX_PATH long since GetVolumePathName('c:\\', buf, 4)
443 # somehow fails on Windows XP
450 # somehow fails on Windows XP
444 size = max(len(realpath), _MAX_PATH) + 1
451 size = max(len(realpath), _MAX_PATH) + 1
445 buf = ctypes.create_string_buffer(size)
452 buf = ctypes.create_string_buffer(size)
446
453
447 if not _kernel32.GetVolumePathNameA(realpath, ctypes.byref(buf), size):
454 if not _kernel32.GetVolumePathNameA(realpath, ctypes.byref(buf), size):
448 raise ctypes.WinError() # Note: WinError is a function
455 raise ctypes.WinError() # Note: WinError is a function
449
456
450 return buf.value
457 return buf.value
451
458
452 def getfstype(path):
459 def getfstype(path):
453 """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)
454
461
455 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.
456 """
463 """
457 volume = getvolumename(path)
464 volume = getvolumename(path)
458
465
459 t = _kernel32.GetDriveTypeA(volume)
466 t = _kernel32.GetDriveTypeA(volume)
460
467
461 if t == _DRIVE_REMOTE:
468 if t == _DRIVE_REMOTE:
462 return 'cifs'
469 return 'cifs'
463 elif t not in (_DRIVE_REMOVABLE, _DRIVE_FIXED, _DRIVE_CDROM,
470 elif t not in (_DRIVE_REMOVABLE, _DRIVE_FIXED, _DRIVE_CDROM,
464 _DRIVE_RAMDISK):
471 _DRIVE_RAMDISK):
465 return None
472 return None
466
473
467 size = _MAX_PATH + 1
474 size = _MAX_PATH + 1
468 name = ctypes.create_string_buffer(size)
475 name = ctypes.create_string_buffer(size)
469
476
470 if not _kernel32.GetVolumeInformationA(volume, None, 0, None, None, None,
477 if not _kernel32.GetVolumeInformationA(volume, None, 0, None, None, None,
471 ctypes.byref(name), size):
478 ctypes.byref(name), size):
472 raise ctypes.WinError() # Note: WinError is a function
479 raise ctypes.WinError() # Note: WinError is a function
473
480
474 return name.value
481 return name.value
475
482
476 def getuser():
483 def getuser():
477 '''return name of current user'''
484 '''return name of current user'''
478 size = _DWORD(300)
485 size = _DWORD(300)
479 buf = ctypes.create_string_buffer(size.value + 1)
486 buf = ctypes.create_string_buffer(size.value + 1)
480 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
487 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
481 raise ctypes.WinError()
488 raise ctypes.WinError()
482 return buf.value
489 return buf.value
483
490
484 _signalhandler = []
491 _signalhandler = []
485
492
486 def setsignalhandler():
493 def setsignalhandler():
487 '''Register a termination handler for console events including
494 '''Register a termination handler for console events including
488 CTRL+C. python signal handlers do not work well with socket
495 CTRL+C. python signal handlers do not work well with socket
489 operations.
496 operations.
490 '''
497 '''
491 def handler(event):
498 def handler(event):
492 _kernel32.ExitProcess(1)
499 _kernel32.ExitProcess(1)
493
500
494 if _signalhandler:
501 if _signalhandler:
495 return # already registered
502 return # already registered
496 h = _SIGNAL_HANDLER(handler)
503 h = _SIGNAL_HANDLER(handler)
497 _signalhandler.append(h) # needed to prevent garbage collection
504 _signalhandler.append(h) # needed to prevent garbage collection
498 if not _kernel32.SetConsoleCtrlHandler(h, True):
505 if not _kernel32.SetConsoleCtrlHandler(h, True):
499 raise ctypes.WinError()
506 raise ctypes.WinError()
500
507
501 def hidewindow():
508 def hidewindow():
502
509
503 def callback(hwnd, pid):
510 def callback(hwnd, pid):
504 wpid = _DWORD()
511 wpid = _DWORD()
505 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
512 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
506 if pid == wpid.value:
513 if pid == wpid.value:
507 _user32.ShowWindow(hwnd, _SW_HIDE)
514 _user32.ShowWindow(hwnd, _SW_HIDE)
508 return False # stop enumerating windows
515 return False # stop enumerating windows
509 return True
516 return True
510
517
511 pid = _kernel32.GetCurrentProcessId()
518 pid = _kernel32.GetCurrentProcessId()
512 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
519 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
513
520
514 def termsize():
521 def termsize():
515 # 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
516 # counted in the line length. On 80 columns consoles, if 80
523 # counted in the line length. On 80 columns consoles, if 80
517 # characters are written, the following CR won't apply on the
524 # characters are written, the following CR won't apply on the
518 # current line but on the new one. Keep room for it.
525 # current line but on the new one. Keep room for it.
519 width = 80 - 1
526 width = 80 - 1
520 height = 25
527 height = 25
521 # Query stderr to avoid problems with redirections
528 # Query stderr to avoid problems with redirections
522 screenbuf = _kernel32.GetStdHandle(
529 screenbuf = _kernel32.GetStdHandle(
523 _STD_ERROR_HANDLE) # don't close the handle returned
530 _STD_ERROR_HANDLE) # don't close the handle returned
524 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
531 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
525 return width, height
532 return width, height
526 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
533 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
527 if not _kernel32.GetConsoleScreenBufferInfo(
534 if not _kernel32.GetConsoleScreenBufferInfo(
528 screenbuf, ctypes.byref(csbi)):
535 screenbuf, ctypes.byref(csbi)):
529 return width, height
536 return width, height
530 width = csbi.srWindow.Right - csbi.srWindow.Left # don't '+ 1'
537 width = csbi.srWindow.Right - csbi.srWindow.Left # don't '+ 1'
531 height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1
538 height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1
532 return width, height
539 return width, height
533
540
534 def enablevtmode():
541 def enablevtmode():
535 '''Enable virtual terminal mode for the associated console. Return True if
542 '''Enable virtual terminal mode for the associated console. Return True if
536 enabled, else False.'''
543 enabled, else False.'''
537
544
538 ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4
545 ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4
539
546
540 handle = _kernel32.GetStdHandle(_STD_OUTPUT_HANDLE) # don't close the handle
547 handle = _kernel32.GetStdHandle(_STD_OUTPUT_HANDLE) # don't close the handle
541 if handle == _INVALID_HANDLE_VALUE:
548 if handle == _INVALID_HANDLE_VALUE:
542 return False
549 return False
543
550
544 mode = _DWORD(0)
551 mode = _DWORD(0)
545
552
546 if not _kernel32.GetConsoleMode(handle, ctypes.byref(mode)):
553 if not _kernel32.GetConsoleMode(handle, ctypes.byref(mode)):
547 return False
554 return False
548
555
549 if (mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0:
556 if (mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0:
550 mode.value |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
557 mode.value |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
551
558
552 if not _kernel32.SetConsoleMode(handle, mode):
559 if not _kernel32.SetConsoleMode(handle, mode):
553 return False
560 return False
554
561
555 return True
562 return True
556
563
557 def spawndetached(args):
564 def spawndetached(args):
558 # No standard library function really spawns a fully detached
565 # No standard library function really spawns a fully detached
559 # process under win32 because they allocate pipes or other objects
566 # process under win32 because they allocate pipes or other objects
560 # to handle standard streams communications. Passing these objects
567 # to handle standard streams communications. Passing these objects
561 # to the child process requires handle inheritance to be enabled
568 # to the child process requires handle inheritance to be enabled
562 # which makes really detached processes impossible.
569 # which makes really detached processes impossible.
563 si = _STARTUPINFO()
570 si = _STARTUPINFO()
564 si.cb = ctypes.sizeof(_STARTUPINFO)
571 si.cb = ctypes.sizeof(_STARTUPINFO)
565
572
566 pi = _PROCESS_INFORMATION()
573 pi = _PROCESS_INFORMATION()
567
574
568 env = ''
575 env = ''
569 for k in encoding.environ:
576 for k in encoding.environ:
570 env += "%s=%s\0" % (k, encoding.environ[k])
577 env += "%s=%s\0" % (k, encoding.environ[k])
571 if not env:
578 if not env:
572 env = '\0'
579 env = '\0'
573 env += '\0'
580 env += '\0'
574
581
575 args = subprocess.list2cmdline(args)
582 args = subprocess.list2cmdline(args)
576
583
577 res = _kernel32.CreateProcessA(
584 res = _kernel32.CreateProcessA(
578 None, args, None, None, False, _CREATE_NO_WINDOW,
585 None, args, None, None, False, _CREATE_NO_WINDOW,
579 env, pycompat.getcwd(), ctypes.byref(si), ctypes.byref(pi))
586 env, pycompat.getcwd(), ctypes.byref(si), ctypes.byref(pi))
580 if not res:
587 if not res:
581 raise ctypes.WinError()
588 raise ctypes.WinError()
582
589
583 return pi.dwProcessId
590 return pi.dwProcessId
584
591
585 def unlink(f):
592 def unlink(f):
586 '''try to implement POSIX' unlink semantics on Windows'''
593 '''try to implement POSIX' unlink semantics on Windows'''
587
594
588 if os.path.isdir(f):
595 if os.path.isdir(f):
589 # use EPERM because it is POSIX prescribed value, even though
596 # use EPERM because it is POSIX prescribed value, even though
590 # unlink(2) on directories returns EISDIR on Linux
597 # unlink(2) on directories returns EISDIR on Linux
591 raise IOError(errno.EPERM,
598 raise IOError(errno.EPERM,
592 "Unlinking directory not permitted: '%s'" % f)
599 "Unlinking directory not permitted: '%s'" % f)
593
600
594 # POSIX allows to unlink and rename open files. Windows has serious
601 # POSIX allows to unlink and rename open files. Windows has serious
595 # problems with doing that:
602 # problems with doing that:
596 # - Calling os.unlink (or os.rename) on a file f fails if f or any
603 # - Calling os.unlink (or os.rename) on a file f fails if f or any
597 # hardlinked copy of f has been opened with Python's open(). There is no
604 # hardlinked copy of f has been opened with Python's open(). There is no
598 # way such a file can be deleted or renamed on Windows (other than
605 # way such a file can be deleted or renamed on Windows (other than
599 # scheduling the delete or rename for the next reboot).
606 # scheduling the delete or rename for the next reboot).
600 # - Calling os.unlink on a file that has been opened with Mercurial's
607 # - Calling os.unlink on a file that has been opened with Mercurial's
601 # posixfile (or comparable methods) will delay the actual deletion of
608 # posixfile (or comparable methods) will delay the actual deletion of
602 # the file for as long as the file is held open. The filename is blocked
609 # the file for as long as the file is held open. The filename is blocked
603 # during that time and cannot be used for recreating a new file under
610 # during that time and cannot be used for recreating a new file under
604 # that same name ("zombie file"). Directories containing such zombie files
611 # that same name ("zombie file"). Directories containing such zombie files
605 # cannot be removed or moved.
612 # cannot be removed or moved.
606 # A file that has been opened with posixfile can be renamed, so we rename
613 # A file that has been opened with posixfile can be renamed, so we rename
607 # f to a random temporary name before calling os.unlink on it. This allows
614 # f to a random temporary name before calling os.unlink on it. This allows
608 # callers to recreate f immediately while having other readers do their
615 # callers to recreate f immediately while having other readers do their
609 # implicit zombie filename blocking on a temporary name.
616 # implicit zombie filename blocking on a temporary name.
610
617
611 for tries in xrange(10):
618 for tries in xrange(10):
612 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
619 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
613 try:
620 try:
614 os.rename(f, temp) # raises OSError EEXIST if temp exists
621 os.rename(f, temp) # raises OSError EEXIST if temp exists
615 break
622 break
616 except OSError as e:
623 except OSError as e:
617 if e.errno != errno.EEXIST:
624 if e.errno != errno.EEXIST:
618 raise
625 raise
619 else:
626 else:
620 raise IOError(errno.EEXIST, "No usable temporary filename found")
627 raise IOError(errno.EEXIST, "No usable temporary filename found")
621
628
622 try:
629 try:
623 os.unlink(temp)
630 os.unlink(temp)
624 except OSError:
631 except OSError:
625 # The unlink might have failed because the READONLY attribute may heave
632 # The unlink might have failed because the READONLY attribute may heave
626 # been set on the original file. Rename works fine with READONLY set,
633 # been set on the original file. Rename works fine with READONLY set,
627 # but not os.unlink. Reset all attributes and try again.
634 # but not os.unlink. Reset all attributes and try again.
628 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
635 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
629 try:
636 try:
630 os.unlink(temp)
637 os.unlink(temp)
631 except OSError:
638 except OSError:
632 # The unlink might have failed due to some very rude AV-Scanners.
639 # The unlink might have failed due to some very rude AV-Scanners.
633 # Leaking a tempfile is the lesser evil than aborting here and
640 # Leaking a tempfile is the lesser evil than aborting here and
634 # leaving some potentially serious inconsistencies.
641 # leaving some potentially serious inconsistencies.
635 pass
642 pass
636
643
637 def makedir(path, notindexed):
644 def makedir(path, notindexed):
638 os.mkdir(path)
645 os.mkdir(path)
639 if notindexed:
646 if notindexed:
640 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
647 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
@@ -1,485 +1,485 b''
1 # windows.py - Windows utility function implementations for Mercurial
1 # windows.py - Windows utility function implementations for Mercurial
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 errno
10 import errno
11 import msvcrt
11 import msvcrt
12 import os
12 import os
13 import re
13 import re
14 import stat
14 import stat
15 import sys
15 import sys
16
16
17 from .i18n import _
17 from .i18n import _
18 from . import (
18 from . import (
19 encoding,
19 encoding,
20 error,
20 error,
21 policy,
21 policy,
22 pycompat,
22 pycompat,
23 win32,
23 win32,
24 )
24 )
25
25
26 try:
26 try:
27 import _winreg as winreg
27 import _winreg as winreg
28 winreg.CloseKey
28 winreg.CloseKey
29 except ImportError:
29 except ImportError:
30 import winreg
30 import winreg
31
31
32 osutil = policy.importmod(r'osutil')
32 osutil = policy.importmod(r'osutil')
33
33
34 getfsmountpoint = win32.getvolumename
34 getfsmountpoint = win32.getvolumename
35 getfstype = win32.getfstype
35 getfstype = win32.getfstype
36 getuser = win32.getuser
36 getuser = win32.getuser
37 hidewindow = win32.hidewindow
37 hidewindow = win32.hidewindow
38 makedir = win32.makedir
38 makedir = win32.makedir
39 nlinks = win32.nlinks
39 nlinks = win32.nlinks
40 oslink = win32.oslink
40 oslink = win32.oslink
41 samedevice = win32.samedevice
41 samedevice = win32.samedevice
42 samefile = win32.samefile
42 samefile = win32.samefile
43 setsignalhandler = win32.setsignalhandler
43 setsignalhandler = win32.setsignalhandler
44 spawndetached = win32.spawndetached
44 spawndetached = win32.spawndetached
45 split = os.path.split
45 split = os.path.split
46 testpid = win32.testpid
46 testpid = win32.testpid
47 unlink = win32.unlink
47 unlink = win32.unlink
48
48
49 umask = 0o022
49 umask = 0o022
50
50
51 class mixedfilemodewrapper(object):
51 class mixedfilemodewrapper(object):
52 """Wraps a file handle when it is opened in read/write mode.
52 """Wraps a file handle when it is opened in read/write mode.
53
53
54 fopen() and fdopen() on Windows have a specific-to-Windows requirement
54 fopen() and fdopen() on Windows have a specific-to-Windows requirement
55 that files opened with mode r+, w+, or a+ make a call to a file positioning
55 that files opened with mode r+, w+, or a+ make a call to a file positioning
56 function when switching between reads and writes. Without this extra call,
56 function when switching between reads and writes. Without this extra call,
57 Python will raise a not very intuitive "IOError: [Errno 0] Error."
57 Python will raise a not very intuitive "IOError: [Errno 0] Error."
58
58
59 This class wraps posixfile instances when the file is opened in read/write
59 This class wraps posixfile instances when the file is opened in read/write
60 mode and automatically adds checks or inserts appropriate file positioning
60 mode and automatically adds checks or inserts appropriate file positioning
61 calls when necessary.
61 calls when necessary.
62 """
62 """
63 OPNONE = 0
63 OPNONE = 0
64 OPREAD = 1
64 OPREAD = 1
65 OPWRITE = 2
65 OPWRITE = 2
66
66
67 def __init__(self, fp):
67 def __init__(self, fp):
68 object.__setattr__(self, r'_fp', fp)
68 object.__setattr__(self, r'_fp', fp)
69 object.__setattr__(self, r'_lastop', 0)
69 object.__setattr__(self, r'_lastop', 0)
70
70
71 def __enter__(self):
71 def __enter__(self):
72 return self._fp.__enter__()
72 return self._fp.__enter__()
73
73
74 def __exit__(self, exc_type, exc_val, exc_tb):
74 def __exit__(self, exc_type, exc_val, exc_tb):
75 self._fp.__exit__(exc_type, exc_val, exc_tb)
75 self._fp.__exit__(exc_type, exc_val, exc_tb)
76
76
77 def __getattr__(self, name):
77 def __getattr__(self, name):
78 return getattr(self._fp, name)
78 return getattr(self._fp, name)
79
79
80 def __setattr__(self, name, value):
80 def __setattr__(self, name, value):
81 return self._fp.__setattr__(name, value)
81 return self._fp.__setattr__(name, value)
82
82
83 def _noopseek(self):
83 def _noopseek(self):
84 self._fp.seek(0, os.SEEK_CUR)
84 self._fp.seek(0, os.SEEK_CUR)
85
85
86 def seek(self, *args, **kwargs):
86 def seek(self, *args, **kwargs):
87 object.__setattr__(self, r'_lastop', self.OPNONE)
87 object.__setattr__(self, r'_lastop', self.OPNONE)
88 return self._fp.seek(*args, **kwargs)
88 return self._fp.seek(*args, **kwargs)
89
89
90 def write(self, d):
90 def write(self, d):
91 if self._lastop == self.OPREAD:
91 if self._lastop == self.OPREAD:
92 self._noopseek()
92 self._noopseek()
93
93
94 object.__setattr__(self, r'_lastop', self.OPWRITE)
94 object.__setattr__(self, r'_lastop', self.OPWRITE)
95 return self._fp.write(d)
95 return self._fp.write(d)
96
96
97 def writelines(self, *args, **kwargs):
97 def writelines(self, *args, **kwargs):
98 if self._lastop == self.OPREAD:
98 if self._lastop == self.OPREAD:
99 self._noopeseek()
99 self._noopeseek()
100
100
101 object.__setattr__(self, r'_lastop', self.OPWRITE)
101 object.__setattr__(self, r'_lastop', self.OPWRITE)
102 return self._fp.writelines(*args, **kwargs)
102 return self._fp.writelines(*args, **kwargs)
103
103
104 def read(self, *args, **kwargs):
104 def read(self, *args, **kwargs):
105 if self._lastop == self.OPWRITE:
105 if self._lastop == self.OPWRITE:
106 self._noopseek()
106 self._noopseek()
107
107
108 object.__setattr__(self, r'_lastop', self.OPREAD)
108 object.__setattr__(self, r'_lastop', self.OPREAD)
109 return self._fp.read(*args, **kwargs)
109 return self._fp.read(*args, **kwargs)
110
110
111 def readline(self, *args, **kwargs):
111 def readline(self, *args, **kwargs):
112 if self._lastop == self.OPWRITE:
112 if self._lastop == self.OPWRITE:
113 self._noopseek()
113 self._noopseek()
114
114
115 object.__setattr__(self, r'_lastop', self.OPREAD)
115 object.__setattr__(self, r'_lastop', self.OPREAD)
116 return self._fp.readline(*args, **kwargs)
116 return self._fp.readline(*args, **kwargs)
117
117
118 def readlines(self, *args, **kwargs):
118 def readlines(self, *args, **kwargs):
119 if self._lastop == self.OPWRITE:
119 if self._lastop == self.OPWRITE:
120 self._noopseek()
120 self._noopseek()
121
121
122 object.__setattr__(self, r'_lastop', self.OPREAD)
122 object.__setattr__(self, r'_lastop', self.OPREAD)
123 return self._fp.readlines(*args, **kwargs)
123 return self._fp.readlines(*args, **kwargs)
124
124
125 def posixfile(name, mode='r', buffering=-1):
125 def posixfile(name, mode='r', buffering=-1):
126 '''Open a file with even more POSIX-like semantics'''
126 '''Open a file with even more POSIX-like semantics'''
127 try:
127 try:
128 fp = osutil.posixfile(name, mode, buffering) # may raise WindowsError
128 fp = osutil.posixfile(name, mode, buffering) # may raise WindowsError
129
129
130 # The position when opening in append mode is implementation defined, so
130 # The position when opening in append mode is implementation defined, so
131 # make it consistent with other platforms, which position at EOF.
131 # make it consistent with other platforms, which position at EOF.
132 if 'a' in mode:
132 if 'a' in mode:
133 fp.seek(0, os.SEEK_END)
133 fp.seek(0, os.SEEK_END)
134
134
135 if '+' in mode:
135 if '+' in mode:
136 return mixedfilemodewrapper(fp)
136 return mixedfilemodewrapper(fp)
137
137
138 return fp
138 return fp
139 except WindowsError as err:
139 except WindowsError as err:
140 # convert to a friendlier exception
140 # convert to a friendlier exception
141 raise IOError(err.errno, '%s: %s' % (
141 raise IOError(err.errno, '%s: %s' % (
142 name, encoding.strtolocal(err.strerror)))
142 name, encoding.strtolocal(err.strerror)))
143
143
144 # may be wrapped by win32mbcs extension
144 # may be wrapped by win32mbcs extension
145 listdir = osutil.listdir
145 listdir = osutil.listdir
146
146
147 class winstdout(object):
147 class winstdout(object):
148 '''stdout on windows misbehaves if sent through a pipe'''
148 '''stdout on windows misbehaves if sent through a pipe'''
149
149
150 def __init__(self, fp):
150 def __init__(self, fp):
151 self.fp = fp
151 self.fp = fp
152
152
153 def __getattr__(self, key):
153 def __getattr__(self, key):
154 return getattr(self.fp, key)
154 return getattr(self.fp, key)
155
155
156 def close(self):
156 def close(self):
157 try:
157 try:
158 self.fp.close()
158 self.fp.close()
159 except IOError:
159 except IOError:
160 pass
160 pass
161
161
162 def write(self, s):
162 def write(self, s):
163 try:
163 try:
164 # This is workaround for "Not enough space" error on
164 # This is workaround for "Not enough space" error on
165 # writing large size of data to console.
165 # writing large size of data to console.
166 limit = 16000
166 limit = 16000
167 l = len(s)
167 l = len(s)
168 start = 0
168 start = 0
169 self.softspace = 0
169 self.softspace = 0
170 while start < l:
170 while start < l:
171 end = start + limit
171 end = start + limit
172 self.fp.write(s[start:end])
172 self.fp.write(s[start:end])
173 start = end
173 start = end
174 except IOError as inst:
174 except IOError as inst:
175 if inst.errno != 0:
175 if inst.errno != 0 and not win32.lasterrorwaspipeerror(inst):
176 raise
176 raise
177 self.close()
177 self.close()
178 raise IOError(errno.EPIPE, 'Broken pipe')
178 raise IOError(errno.EPIPE, 'Broken pipe')
179
179
180 def flush(self):
180 def flush(self):
181 try:
181 try:
182 return self.fp.flush()
182 return self.fp.flush()
183 except IOError as inst:
183 except IOError as inst:
184 if inst.errno != errno.EINVAL:
184 if not win32.lasterrorwaspipeerror(inst):
185 raise
185 raise
186 raise IOError(errno.EPIPE, 'Broken pipe')
186 raise IOError(errno.EPIPE, 'Broken pipe')
187
187
188 def _is_win_9x():
188 def _is_win_9x():
189 '''return true if run on windows 95, 98 or me.'''
189 '''return true if run on windows 95, 98 or me.'''
190 try:
190 try:
191 return sys.getwindowsversion()[3] == 1
191 return sys.getwindowsversion()[3] == 1
192 except AttributeError:
192 except AttributeError:
193 return 'command' in encoding.environ.get('comspec', '')
193 return 'command' in encoding.environ.get('comspec', '')
194
194
195 def openhardlinks():
195 def openhardlinks():
196 return not _is_win_9x()
196 return not _is_win_9x()
197
197
198 def parsepatchoutput(output_line):
198 def parsepatchoutput(output_line):
199 """parses the output produced by patch and returns the filename"""
199 """parses the output produced by patch and returns the filename"""
200 pf = output_line[14:]
200 pf = output_line[14:]
201 if pf[0] == '`':
201 if pf[0] == '`':
202 pf = pf[1:-1] # Remove the quotes
202 pf = pf[1:-1] # Remove the quotes
203 return pf
203 return pf
204
204
205 def sshargs(sshcmd, host, user, port):
205 def sshargs(sshcmd, host, user, port):
206 '''Build argument list for ssh or Plink'''
206 '''Build argument list for ssh or Plink'''
207 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
207 pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
208 args = user and ("%s@%s" % (user, host)) or host
208 args = user and ("%s@%s" % (user, host)) or host
209 if args.startswith('-') or args.startswith('/'):
209 if args.startswith('-') or args.startswith('/'):
210 raise error.Abort(
210 raise error.Abort(
211 _('illegal ssh hostname or username starting with - or /: %s') %
211 _('illegal ssh hostname or username starting with - or /: %s') %
212 args)
212 args)
213 args = shellquote(args)
213 args = shellquote(args)
214 if port:
214 if port:
215 args = '%s %s %s' % (pflag, shellquote(port), args)
215 args = '%s %s %s' % (pflag, shellquote(port), args)
216 return args
216 return args
217
217
218 def setflags(f, l, x):
218 def setflags(f, l, x):
219 pass
219 pass
220
220
221 def copymode(src, dst, mode=None):
221 def copymode(src, dst, mode=None):
222 pass
222 pass
223
223
224 def checkexec(path):
224 def checkexec(path):
225 return False
225 return False
226
226
227 def checklink(path):
227 def checklink(path):
228 return False
228 return False
229
229
230 def setbinary(fd):
230 def setbinary(fd):
231 # When run without console, pipes may expose invalid
231 # When run without console, pipes may expose invalid
232 # fileno(), usually set to -1.
232 # fileno(), usually set to -1.
233 fno = getattr(fd, 'fileno', None)
233 fno = getattr(fd, 'fileno', None)
234 if fno is not None and fno() >= 0:
234 if fno is not None and fno() >= 0:
235 msvcrt.setmode(fno(), os.O_BINARY)
235 msvcrt.setmode(fno(), os.O_BINARY)
236
236
237 def pconvert(path):
237 def pconvert(path):
238 return path.replace(pycompat.ossep, '/')
238 return path.replace(pycompat.ossep, '/')
239
239
240 def localpath(path):
240 def localpath(path):
241 return path.replace('/', '\\')
241 return path.replace('/', '\\')
242
242
243 def normpath(path):
243 def normpath(path):
244 return pconvert(os.path.normpath(path))
244 return pconvert(os.path.normpath(path))
245
245
246 def normcase(path):
246 def normcase(path):
247 return encoding.upper(path) # NTFS compares via upper()
247 return encoding.upper(path) # NTFS compares via upper()
248
248
249 # see posix.py for definitions
249 # see posix.py for definitions
250 normcasespec = encoding.normcasespecs.upper
250 normcasespec = encoding.normcasespecs.upper
251 normcasefallback = encoding.upperfallback
251 normcasefallback = encoding.upperfallback
252
252
253 def samestat(s1, s2):
253 def samestat(s1, s2):
254 return False
254 return False
255
255
256 # A sequence of backslashes is special iff it precedes a double quote:
256 # A sequence of backslashes is special iff it precedes a double quote:
257 # - if there's an even number of backslashes, the double quote is not
257 # - if there's an even number of backslashes, the double quote is not
258 # quoted (i.e. it ends the quoted region)
258 # quoted (i.e. it ends the quoted region)
259 # - if there's an odd number of backslashes, the double quote is quoted
259 # - if there's an odd number of backslashes, the double quote is quoted
260 # - in both cases, every pair of backslashes is unquoted into a single
260 # - in both cases, every pair of backslashes is unquoted into a single
261 # backslash
261 # backslash
262 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
262 # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
263 # So, to quote a string, we must surround it in double quotes, double
263 # So, to quote a string, we must surround it in double quotes, double
264 # the number of backslashes that precede double quotes and add another
264 # the number of backslashes that precede double quotes and add another
265 # backslash before every double quote (being careful with the double
265 # backslash before every double quote (being careful with the double
266 # quote we've appended to the end)
266 # quote we've appended to the end)
267 _quotere = None
267 _quotere = None
268 _needsshellquote = None
268 _needsshellquote = None
269 def shellquote(s):
269 def shellquote(s):
270 r"""
270 r"""
271 >>> shellquote(br'C:\Users\xyz')
271 >>> shellquote(br'C:\Users\xyz')
272 '"C:\\Users\\xyz"'
272 '"C:\\Users\\xyz"'
273 >>> shellquote(br'C:\Users\xyz/mixed')
273 >>> shellquote(br'C:\Users\xyz/mixed')
274 '"C:\\Users\\xyz/mixed"'
274 '"C:\\Users\\xyz/mixed"'
275 >>> # Would be safe not to quote too, since it is all double backslashes
275 >>> # Would be safe not to quote too, since it is all double backslashes
276 >>> shellquote(br'C:\\Users\\xyz')
276 >>> shellquote(br'C:\\Users\\xyz')
277 '"C:\\\\Users\\\\xyz"'
277 '"C:\\\\Users\\\\xyz"'
278 >>> # But this must be quoted
278 >>> # But this must be quoted
279 >>> shellquote(br'C:\\Users\\xyz/abc')
279 >>> shellquote(br'C:\\Users\\xyz/abc')
280 '"C:\\\\Users\\\\xyz/abc"'
280 '"C:\\\\Users\\\\xyz/abc"'
281 """
281 """
282 global _quotere
282 global _quotere
283 if _quotere is None:
283 if _quotere is None:
284 _quotere = re.compile(r'(\\*)("|\\$)')
284 _quotere = re.compile(r'(\\*)("|\\$)')
285 global _needsshellquote
285 global _needsshellquote
286 if _needsshellquote is None:
286 if _needsshellquote is None:
287 # ":" is also treated as "safe character", because it is used as a part
287 # ":" is also treated as "safe character", because it is used as a part
288 # of path name on Windows. "\" is also part of a path name, but isn't
288 # of path name on Windows. "\" is also part of a path name, but isn't
289 # safe because shlex.split() (kind of) treats it as an escape char and
289 # safe because shlex.split() (kind of) treats it as an escape char and
290 # drops it. It will leave the next character, even if it is another
290 # drops it. It will leave the next character, even if it is another
291 # "\".
291 # "\".
292 _needsshellquote = re.compile(r'[^a-zA-Z0-9._:/-]').search
292 _needsshellquote = re.compile(r'[^a-zA-Z0-9._:/-]').search
293 if s and not _needsshellquote(s) and not _quotere.search(s):
293 if s and not _needsshellquote(s) and not _quotere.search(s):
294 # "s" shouldn't have to be quoted
294 # "s" shouldn't have to be quoted
295 return s
295 return s
296 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
296 return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
297
297
298 def _unquote(s):
298 def _unquote(s):
299 if s.startswith(b'"') and s.endswith(b'"'):
299 if s.startswith(b'"') and s.endswith(b'"'):
300 return s[1:-1]
300 return s[1:-1]
301 return s
301 return s
302
302
303 def shellsplit(s):
303 def shellsplit(s):
304 """Parse a command string in cmd.exe way (best-effort)"""
304 """Parse a command string in cmd.exe way (best-effort)"""
305 return pycompat.maplist(_unquote, pycompat.shlexsplit(s, posix=False))
305 return pycompat.maplist(_unquote, pycompat.shlexsplit(s, posix=False))
306
306
307 def quotecommand(cmd):
307 def quotecommand(cmd):
308 """Build a command string suitable for os.popen* calls."""
308 """Build a command string suitable for os.popen* calls."""
309 if sys.version_info < (2, 7, 1):
309 if sys.version_info < (2, 7, 1):
310 # Python versions since 2.7.1 do this extra quoting themselves
310 # Python versions since 2.7.1 do this extra quoting themselves
311 return '"' + cmd + '"'
311 return '"' + cmd + '"'
312 return cmd
312 return cmd
313
313
314 # if you change this stub into a real check, please try to implement the
314 # if you change this stub into a real check, please try to implement the
315 # username and groupname functions above, too.
315 # username and groupname functions above, too.
316 def isowner(st):
316 def isowner(st):
317 return True
317 return True
318
318
319 def findexe(command):
319 def findexe(command):
320 '''Find executable for command searching like cmd.exe does.
320 '''Find executable for command searching like cmd.exe does.
321 If command is a basename then PATH is searched for command.
321 If command is a basename then PATH is searched for command.
322 PATH isn't searched if command is an absolute or relative path.
322 PATH isn't searched if command is an absolute or relative path.
323 An extension from PATHEXT is found and added if not present.
323 An extension from PATHEXT is found and added if not present.
324 If command isn't found None is returned.'''
324 If command isn't found None is returned.'''
325 pathext = encoding.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
325 pathext = encoding.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
326 pathexts = [ext for ext in pathext.lower().split(pycompat.ospathsep)]
326 pathexts = [ext for ext in pathext.lower().split(pycompat.ospathsep)]
327 if os.path.splitext(command)[1].lower() in pathexts:
327 if os.path.splitext(command)[1].lower() in pathexts:
328 pathexts = ['']
328 pathexts = ['']
329
329
330 def findexisting(pathcommand):
330 def findexisting(pathcommand):
331 'Will append extension (if needed) and return existing file'
331 'Will append extension (if needed) and return existing file'
332 for ext in pathexts:
332 for ext in pathexts:
333 executable = pathcommand + ext
333 executable = pathcommand + ext
334 if os.path.exists(executable):
334 if os.path.exists(executable):
335 return executable
335 return executable
336 return None
336 return None
337
337
338 if pycompat.ossep in command:
338 if pycompat.ossep in command:
339 return findexisting(command)
339 return findexisting(command)
340
340
341 for path in encoding.environ.get('PATH', '').split(pycompat.ospathsep):
341 for path in encoding.environ.get('PATH', '').split(pycompat.ospathsep):
342 executable = findexisting(os.path.join(path, command))
342 executable = findexisting(os.path.join(path, command))
343 if executable is not None:
343 if executable is not None:
344 return executable
344 return executable
345 return findexisting(os.path.expanduser(os.path.expandvars(command)))
345 return findexisting(os.path.expanduser(os.path.expandvars(command)))
346
346
347 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK}
347 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK}
348
348
349 def statfiles(files):
349 def statfiles(files):
350 '''Stat each file in files. Yield each stat, or None if a file
350 '''Stat each file in files. Yield each stat, or None if a file
351 does not exist or has a type we don't care about.
351 does not exist or has a type we don't care about.
352
352
353 Cluster and cache stat per directory to minimize number of OS stat calls.'''
353 Cluster and cache stat per directory to minimize number of OS stat calls.'''
354 dircache = {} # dirname -> filename -> status | None if file does not exist
354 dircache = {} # dirname -> filename -> status | None if file does not exist
355 getkind = stat.S_IFMT
355 getkind = stat.S_IFMT
356 for nf in files:
356 for nf in files:
357 nf = normcase(nf)
357 nf = normcase(nf)
358 dir, base = os.path.split(nf)
358 dir, base = os.path.split(nf)
359 if not dir:
359 if not dir:
360 dir = '.'
360 dir = '.'
361 cache = dircache.get(dir, None)
361 cache = dircache.get(dir, None)
362 if cache is None:
362 if cache is None:
363 try:
363 try:
364 dmap = dict([(normcase(n), s)
364 dmap = dict([(normcase(n), s)
365 for n, k, s in listdir(dir, True)
365 for n, k, s in listdir(dir, True)
366 if getkind(s.st_mode) in _wantedkinds])
366 if getkind(s.st_mode) in _wantedkinds])
367 except OSError as err:
367 except OSError as err:
368 # Python >= 2.5 returns ENOENT and adds winerror field
368 # Python >= 2.5 returns ENOENT and adds winerror field
369 # EINVAL is raised if dir is not a directory.
369 # EINVAL is raised if dir is not a directory.
370 if err.errno not in (errno.ENOENT, errno.EINVAL,
370 if err.errno not in (errno.ENOENT, errno.EINVAL,
371 errno.ENOTDIR):
371 errno.ENOTDIR):
372 raise
372 raise
373 dmap = {}
373 dmap = {}
374 cache = dircache.setdefault(dir, dmap)
374 cache = dircache.setdefault(dir, dmap)
375 yield cache.get(base, None)
375 yield cache.get(base, None)
376
376
377 def username(uid=None):
377 def username(uid=None):
378 """Return the name of the user with the given uid.
378 """Return the name of the user with the given uid.
379
379
380 If uid is None, return the name of the current user."""
380 If uid is None, return the name of the current user."""
381 return None
381 return None
382
382
383 def groupname(gid=None):
383 def groupname(gid=None):
384 """Return the name of the group with the given gid.
384 """Return the name of the group with the given gid.
385
385
386 If gid is None, return the name of the current group."""
386 If gid is None, return the name of the current group."""
387 return None
387 return None
388
388
389 def removedirs(name):
389 def removedirs(name):
390 """special version of os.removedirs that does not remove symlinked
390 """special version of os.removedirs that does not remove symlinked
391 directories or junction points if they actually contain files"""
391 directories or junction points if they actually contain files"""
392 if listdir(name):
392 if listdir(name):
393 return
393 return
394 os.rmdir(name)
394 os.rmdir(name)
395 head, tail = os.path.split(name)
395 head, tail = os.path.split(name)
396 if not tail:
396 if not tail:
397 head, tail = os.path.split(head)
397 head, tail = os.path.split(head)
398 while head and tail:
398 while head and tail:
399 try:
399 try:
400 if listdir(head):
400 if listdir(head):
401 return
401 return
402 os.rmdir(head)
402 os.rmdir(head)
403 except (ValueError, OSError):
403 except (ValueError, OSError):
404 break
404 break
405 head, tail = os.path.split(head)
405 head, tail = os.path.split(head)
406
406
407 def rename(src, dst):
407 def rename(src, dst):
408 '''atomically rename file src to dst, replacing dst if it exists'''
408 '''atomically rename file src to dst, replacing dst if it exists'''
409 try:
409 try:
410 os.rename(src, dst)
410 os.rename(src, dst)
411 except OSError as e:
411 except OSError as e:
412 if e.errno != errno.EEXIST:
412 if e.errno != errno.EEXIST:
413 raise
413 raise
414 unlink(dst)
414 unlink(dst)
415 os.rename(src, dst)
415 os.rename(src, dst)
416
416
417 def gethgcmd():
417 def gethgcmd():
418 return [sys.executable] + sys.argv[:1]
418 return [sys.executable] + sys.argv[:1]
419
419
420 def groupmembers(name):
420 def groupmembers(name):
421 # Don't support groups on Windows for now
421 # Don't support groups on Windows for now
422 raise KeyError
422 raise KeyError
423
423
424 def isexec(f):
424 def isexec(f):
425 return False
425 return False
426
426
427 class cachestat(object):
427 class cachestat(object):
428 def __init__(self, path):
428 def __init__(self, path):
429 pass
429 pass
430
430
431 def cacheable(self):
431 def cacheable(self):
432 return False
432 return False
433
433
434 def lookupreg(key, valname=None, scope=None):
434 def lookupreg(key, valname=None, scope=None):
435 ''' Look up a key/value name in the Windows registry.
435 ''' Look up a key/value name in the Windows registry.
436
436
437 valname: value name. If unspecified, the default value for the key
437 valname: value name. If unspecified, the default value for the key
438 is used.
438 is used.
439 scope: optionally specify scope for registry lookup, this can be
439 scope: optionally specify scope for registry lookup, this can be
440 a sequence of scopes to look up in order. Default (CURRENT_USER,
440 a sequence of scopes to look up in order. Default (CURRENT_USER,
441 LOCAL_MACHINE).
441 LOCAL_MACHINE).
442 '''
442 '''
443 if scope is None:
443 if scope is None:
444 scope = (winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE)
444 scope = (winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE)
445 elif not isinstance(scope, (list, tuple)):
445 elif not isinstance(scope, (list, tuple)):
446 scope = (scope,)
446 scope = (scope,)
447 for s in scope:
447 for s in scope:
448 try:
448 try:
449 val = winreg.QueryValueEx(winreg.OpenKey(s, key), valname)[0]
449 val = winreg.QueryValueEx(winreg.OpenKey(s, key), valname)[0]
450 # never let a Unicode string escape into the wild
450 # never let a Unicode string escape into the wild
451 return encoding.unitolocal(val)
451 return encoding.unitolocal(val)
452 except EnvironmentError:
452 except EnvironmentError:
453 pass
453 pass
454
454
455 expandglobs = True
455 expandglobs = True
456
456
457 def statislink(st):
457 def statislink(st):
458 '''check whether a stat result is a symlink'''
458 '''check whether a stat result is a symlink'''
459 return False
459 return False
460
460
461 def statisexec(st):
461 def statisexec(st):
462 '''check whether a stat result is an executable file'''
462 '''check whether a stat result is an executable file'''
463 return False
463 return False
464
464
465 def poll(fds):
465 def poll(fds):
466 # see posix.py for description
466 # see posix.py for description
467 raise NotImplementedError()
467 raise NotImplementedError()
468
468
469 def readpipe(pipe):
469 def readpipe(pipe):
470 """Read all available data from a pipe."""
470 """Read all available data from a pipe."""
471 chunks = []
471 chunks = []
472 while True:
472 while True:
473 size = win32.peekpipe(pipe)
473 size = win32.peekpipe(pipe)
474 if not size:
474 if not size:
475 break
475 break
476
476
477 s = pipe.read(size)
477 s = pipe.read(size)
478 if not s:
478 if not s:
479 break
479 break
480 chunks.append(s)
480 chunks.append(s)
481
481
482 return ''.join(chunks)
482 return ''.join(chunks)
483
483
484 def bindunixsocket(sock, path):
484 def bindunixsocket(sock, path):
485 raise NotImplementedError('unsupported platform')
485 raise NotImplementedError('unsupported platform')
General Comments 0
You need to be logged in to leave comments. Login now