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