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