##// END OF EJS Templates
win32: clean up use of two-argument raise...
Augie Fackler -
r18175:fd3f8b87 default
parent child Browse files
Show More
@@ -1,393 +1,393 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 import ctypes, errno, os, subprocess, random
8 import ctypes, errno, os, subprocess, random
9
9
10 _kernel32 = ctypes.windll.kernel32
10 _kernel32 = ctypes.windll.kernel32
11 _advapi32 = ctypes.windll.advapi32
11 _advapi32 = ctypes.windll.advapi32
12 _user32 = ctypes.windll.user32
12 _user32 = ctypes.windll.user32
13
13
14 _BOOL = ctypes.c_long
14 _BOOL = ctypes.c_long
15 _WORD = ctypes.c_ushort
15 _WORD = ctypes.c_ushort
16 _DWORD = ctypes.c_ulong
16 _DWORD = ctypes.c_ulong
17 _UINT = ctypes.c_uint
17 _UINT = ctypes.c_uint
18 _LONG = ctypes.c_long
18 _LONG = ctypes.c_long
19 _LPCSTR = _LPSTR = ctypes.c_char_p
19 _LPCSTR = _LPSTR = ctypes.c_char_p
20 _HANDLE = ctypes.c_void_p
20 _HANDLE = ctypes.c_void_p
21 _HWND = _HANDLE
21 _HWND = _HANDLE
22
22
23 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
23 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
24
24
25 # GetLastError
25 # GetLastError
26 _ERROR_SUCCESS = 0
26 _ERROR_SUCCESS = 0
27 _ERROR_INVALID_PARAMETER = 87
27 _ERROR_INVALID_PARAMETER = 87
28 _ERROR_INSUFFICIENT_BUFFER = 122
28 _ERROR_INSUFFICIENT_BUFFER = 122
29
29
30 # WPARAM is defined as UINT_PTR (unsigned type)
30 # WPARAM is defined as UINT_PTR (unsigned type)
31 # LPARAM is defined as LONG_PTR (signed type)
31 # LPARAM is defined as LONG_PTR (signed type)
32 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
32 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
33 _WPARAM = ctypes.c_ulong
33 _WPARAM = ctypes.c_ulong
34 _LPARAM = ctypes.c_long
34 _LPARAM = ctypes.c_long
35 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
35 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
36 _WPARAM = ctypes.c_ulonglong
36 _WPARAM = ctypes.c_ulonglong
37 _LPARAM = ctypes.c_longlong
37 _LPARAM = ctypes.c_longlong
38
38
39 class _FILETIME(ctypes.Structure):
39 class _FILETIME(ctypes.Structure):
40 _fields_ = [('dwLowDateTime', _DWORD),
40 _fields_ = [('dwLowDateTime', _DWORD),
41 ('dwHighDateTime', _DWORD)]
41 ('dwHighDateTime', _DWORD)]
42
42
43 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
43 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
44 _fields_ = [('dwFileAttributes', _DWORD),
44 _fields_ = [('dwFileAttributes', _DWORD),
45 ('ftCreationTime', _FILETIME),
45 ('ftCreationTime', _FILETIME),
46 ('ftLastAccessTime', _FILETIME),
46 ('ftLastAccessTime', _FILETIME),
47 ('ftLastWriteTime', _FILETIME),
47 ('ftLastWriteTime', _FILETIME),
48 ('dwVolumeSerialNumber', _DWORD),
48 ('dwVolumeSerialNumber', _DWORD),
49 ('nFileSizeHigh', _DWORD),
49 ('nFileSizeHigh', _DWORD),
50 ('nFileSizeLow', _DWORD),
50 ('nFileSizeLow', _DWORD),
51 ('nNumberOfLinks', _DWORD),
51 ('nNumberOfLinks', _DWORD),
52 ('nFileIndexHigh', _DWORD),
52 ('nFileIndexHigh', _DWORD),
53 ('nFileIndexLow', _DWORD)]
53 ('nFileIndexLow', _DWORD)]
54
54
55 # CreateFile
55 # CreateFile
56 _FILE_SHARE_READ = 0x00000001
56 _FILE_SHARE_READ = 0x00000001
57 _FILE_SHARE_WRITE = 0x00000002
57 _FILE_SHARE_WRITE = 0x00000002
58 _FILE_SHARE_DELETE = 0x00000004
58 _FILE_SHARE_DELETE = 0x00000004
59
59
60 _OPEN_EXISTING = 3
60 _OPEN_EXISTING = 3
61
61
62 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
62 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
63
63
64 # SetFileAttributes
64 # SetFileAttributes
65 _FILE_ATTRIBUTE_NORMAL = 0x80
65 _FILE_ATTRIBUTE_NORMAL = 0x80
66 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
66 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
67
67
68 # Process Security and Access Rights
68 # Process Security and Access Rights
69 _PROCESS_QUERY_INFORMATION = 0x0400
69 _PROCESS_QUERY_INFORMATION = 0x0400
70
70
71 # GetExitCodeProcess
71 # GetExitCodeProcess
72 _STILL_ACTIVE = 259
72 _STILL_ACTIVE = 259
73
73
74 class _STARTUPINFO(ctypes.Structure):
74 class _STARTUPINFO(ctypes.Structure):
75 _fields_ = [('cb', _DWORD),
75 _fields_ = [('cb', _DWORD),
76 ('lpReserved', _LPSTR),
76 ('lpReserved', _LPSTR),
77 ('lpDesktop', _LPSTR),
77 ('lpDesktop', _LPSTR),
78 ('lpTitle', _LPSTR),
78 ('lpTitle', _LPSTR),
79 ('dwX', _DWORD),
79 ('dwX', _DWORD),
80 ('dwY', _DWORD),
80 ('dwY', _DWORD),
81 ('dwXSize', _DWORD),
81 ('dwXSize', _DWORD),
82 ('dwYSize', _DWORD),
82 ('dwYSize', _DWORD),
83 ('dwXCountChars', _DWORD),
83 ('dwXCountChars', _DWORD),
84 ('dwYCountChars', _DWORD),
84 ('dwYCountChars', _DWORD),
85 ('dwFillAttribute', _DWORD),
85 ('dwFillAttribute', _DWORD),
86 ('dwFlags', _DWORD),
86 ('dwFlags', _DWORD),
87 ('wShowWindow', _WORD),
87 ('wShowWindow', _WORD),
88 ('cbReserved2', _WORD),
88 ('cbReserved2', _WORD),
89 ('lpReserved2', ctypes.c_char_p),
89 ('lpReserved2', ctypes.c_char_p),
90 ('hStdInput', _HANDLE),
90 ('hStdInput', _HANDLE),
91 ('hStdOutput', _HANDLE),
91 ('hStdOutput', _HANDLE),
92 ('hStdError', _HANDLE)]
92 ('hStdError', _HANDLE)]
93
93
94 class _PROCESS_INFORMATION(ctypes.Structure):
94 class _PROCESS_INFORMATION(ctypes.Structure):
95 _fields_ = [('hProcess', _HANDLE),
95 _fields_ = [('hProcess', _HANDLE),
96 ('hThread', _HANDLE),
96 ('hThread', _HANDLE),
97 ('dwProcessId', _DWORD),
97 ('dwProcessId', _DWORD),
98 ('dwThreadId', _DWORD)]
98 ('dwThreadId', _DWORD)]
99
99
100 _CREATE_NO_WINDOW = 0x08000000
100 _CREATE_NO_WINDOW = 0x08000000
101 _SW_HIDE = 0
101 _SW_HIDE = 0
102
102
103 class _COORD(ctypes.Structure):
103 class _COORD(ctypes.Structure):
104 _fields_ = [('X', ctypes.c_short),
104 _fields_ = [('X', ctypes.c_short),
105 ('Y', ctypes.c_short)]
105 ('Y', ctypes.c_short)]
106
106
107 class _SMALL_RECT(ctypes.Structure):
107 class _SMALL_RECT(ctypes.Structure):
108 _fields_ = [('Left', ctypes.c_short),
108 _fields_ = [('Left', ctypes.c_short),
109 ('Top', ctypes.c_short),
109 ('Top', ctypes.c_short),
110 ('Right', ctypes.c_short),
110 ('Right', ctypes.c_short),
111 ('Bottom', ctypes.c_short)]
111 ('Bottom', ctypes.c_short)]
112
112
113 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
113 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
114 _fields_ = [('dwSize', _COORD),
114 _fields_ = [('dwSize', _COORD),
115 ('dwCursorPosition', _COORD),
115 ('dwCursorPosition', _COORD),
116 ('wAttributes', _WORD),
116 ('wAttributes', _WORD),
117 ('srWindow', _SMALL_RECT),
117 ('srWindow', _SMALL_RECT),
118 ('dwMaximumWindowSize', _COORD)]
118 ('dwMaximumWindowSize', _COORD)]
119
119
120 _STD_ERROR_HANDLE = _DWORD(-12).value
120 _STD_ERROR_HANDLE = _DWORD(-12).value
121
121
122 # types of parameters of C functions used (required by pypy)
122 # types of parameters of C functions used (required by pypy)
123
123
124 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
124 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
125 _DWORD, _DWORD, _HANDLE]
125 _DWORD, _DWORD, _HANDLE]
126 _kernel32.CreateFileA.restype = _HANDLE
126 _kernel32.CreateFileA.restype = _HANDLE
127
127
128 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
128 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
129 _kernel32.GetFileInformationByHandle.restype = _BOOL
129 _kernel32.GetFileInformationByHandle.restype = _BOOL
130
130
131 _kernel32.CloseHandle.argtypes = [_HANDLE]
131 _kernel32.CloseHandle.argtypes = [_HANDLE]
132 _kernel32.CloseHandle.restype = _BOOL
132 _kernel32.CloseHandle.restype = _BOOL
133
133
134 try:
134 try:
135 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
135 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
136 _kernel32.CreateHardLinkA.restype = _BOOL
136 _kernel32.CreateHardLinkA.restype = _BOOL
137 except AttributeError:
137 except AttributeError:
138 pass
138 pass
139
139
140 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
140 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
141 _kernel32.SetFileAttributesA.restype = _BOOL
141 _kernel32.SetFileAttributesA.restype = _BOOL
142
142
143 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
143 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
144 _kernel32.OpenProcess.restype = _HANDLE
144 _kernel32.OpenProcess.restype = _HANDLE
145
145
146 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
146 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
147 _kernel32.GetExitCodeProcess.restype = _BOOL
147 _kernel32.GetExitCodeProcess.restype = _BOOL
148
148
149 _kernel32.GetLastError.argtypes = []
149 _kernel32.GetLastError.argtypes = []
150 _kernel32.GetLastError.restype = _DWORD
150 _kernel32.GetLastError.restype = _DWORD
151
151
152 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
152 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
153 _kernel32.GetModuleFileNameA.restype = _DWORD
153 _kernel32.GetModuleFileNameA.restype = _DWORD
154
154
155 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
155 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
156 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
156 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
157 ctypes.c_void_p]
157 ctypes.c_void_p]
158 _kernel32.CreateProcessA.restype = _BOOL
158 _kernel32.CreateProcessA.restype = _BOOL
159
159
160 _kernel32.ExitProcess.argtypes = [_UINT]
160 _kernel32.ExitProcess.argtypes = [_UINT]
161 _kernel32.ExitProcess.restype = None
161 _kernel32.ExitProcess.restype = None
162
162
163 _kernel32.GetCurrentProcessId.argtypes = []
163 _kernel32.GetCurrentProcessId.argtypes = []
164 _kernel32.GetCurrentProcessId.restype = _DWORD
164 _kernel32.GetCurrentProcessId.restype = _DWORD
165
165
166 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
166 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
167 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
167 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
168 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
168 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
169
169
170 _kernel32.GetStdHandle.argtypes = [_DWORD]
170 _kernel32.GetStdHandle.argtypes = [_DWORD]
171 _kernel32.GetStdHandle.restype = _HANDLE
171 _kernel32.GetStdHandle.restype = _HANDLE
172
172
173 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
173 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
174 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
174 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
175
175
176 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
176 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
177 _advapi32.GetUserNameA.restype = _BOOL
177 _advapi32.GetUserNameA.restype = _BOOL
178
178
179 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
179 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
180 _user32.GetWindowThreadProcessId.restype = _DWORD
180 _user32.GetWindowThreadProcessId.restype = _DWORD
181
181
182 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
182 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
183 _user32.ShowWindow.restype = _BOOL
183 _user32.ShowWindow.restype = _BOOL
184
184
185 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
185 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
186 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
186 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
187 _user32.EnumWindows.restype = _BOOL
187 _user32.EnumWindows.restype = _BOOL
188
188
189 def _raiseoserror(name):
189 def _raiseoserror(name):
190 err = ctypes.WinError()
190 err = ctypes.WinError()
191 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
191 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
192
192
193 def _getfileinfo(name):
193 def _getfileinfo(name):
194 fh = _kernel32.CreateFileA(name, 0,
194 fh = _kernel32.CreateFileA(name, 0,
195 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
195 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
196 None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
196 None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
197 if fh == _INVALID_HANDLE_VALUE:
197 if fh == _INVALID_HANDLE_VALUE:
198 _raiseoserror(name)
198 _raiseoserror(name)
199 try:
199 try:
200 fi = _BY_HANDLE_FILE_INFORMATION()
200 fi = _BY_HANDLE_FILE_INFORMATION()
201 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
201 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
202 _raiseoserror(name)
202 _raiseoserror(name)
203 return fi
203 return fi
204 finally:
204 finally:
205 _kernel32.CloseHandle(fh)
205 _kernel32.CloseHandle(fh)
206
206
207 def oslink(src, dst):
207 def oslink(src, dst):
208 try:
208 try:
209 if not _kernel32.CreateHardLinkA(dst, src, None):
209 if not _kernel32.CreateHardLinkA(dst, src, None):
210 _raiseoserror(src)
210 _raiseoserror(src)
211 except AttributeError: # Wine doesn't support this function
211 except AttributeError: # Wine doesn't support this function
212 _raiseoserror(src)
212 _raiseoserror(src)
213
213
214 def nlinks(name):
214 def nlinks(name):
215 '''return number of hardlinks for the given file'''
215 '''return number of hardlinks for the given file'''
216 return _getfileinfo(name).nNumberOfLinks
216 return _getfileinfo(name).nNumberOfLinks
217
217
218 def samefile(path1, path2):
218 def samefile(path1, path2):
219 '''Returns whether path1 and path2 refer to the same file or directory.'''
219 '''Returns whether path1 and path2 refer to the same file or directory.'''
220 res1 = _getfileinfo(path1)
220 res1 = _getfileinfo(path1)
221 res2 = _getfileinfo(path2)
221 res2 = _getfileinfo(path2)
222 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
222 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
223 and res1.nFileIndexHigh == res2.nFileIndexHigh
223 and res1.nFileIndexHigh == res2.nFileIndexHigh
224 and res1.nFileIndexLow == res2.nFileIndexLow)
224 and res1.nFileIndexLow == res2.nFileIndexLow)
225
225
226 def samedevice(path1, path2):
226 def samedevice(path1, path2):
227 '''Returns whether path1 and path2 are on the same device.'''
227 '''Returns whether path1 and path2 are on the same device.'''
228 res1 = _getfileinfo(path1)
228 res1 = _getfileinfo(path1)
229 res2 = _getfileinfo(path2)
229 res2 = _getfileinfo(path2)
230 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
230 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
231
231
232 def testpid(pid):
232 def testpid(pid):
233 '''return True if pid is still running or unable to
233 '''return True if pid is still running or unable to
234 determine, False otherwise'''
234 determine, False otherwise'''
235 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
235 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
236 if h:
236 if h:
237 try:
237 try:
238 status = _DWORD()
238 status = _DWORD()
239 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
239 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
240 return status.value == _STILL_ACTIVE
240 return status.value == _STILL_ACTIVE
241 finally:
241 finally:
242 _kernel32.CloseHandle(h)
242 _kernel32.CloseHandle(h)
243 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
243 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
244
244
245 def executablepath():
245 def executablepath():
246 '''return full path of hg.exe'''
246 '''return full path of hg.exe'''
247 size = 600
247 size = 600
248 buf = ctypes.create_string_buffer(size + 1)
248 buf = ctypes.create_string_buffer(size + 1)
249 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
249 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
250 if len == 0:
250 if len == 0:
251 raise ctypes.WinError
251 raise ctypes.WinError
252 elif len == size:
252 elif len == size:
253 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
253 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
254 return buf.value
254 return buf.value
255
255
256 def getuser():
256 def getuser():
257 '''return name of current user'''
257 '''return name of current user'''
258 size = _DWORD(300)
258 size = _DWORD(300)
259 buf = ctypes.create_string_buffer(size.value + 1)
259 buf = ctypes.create_string_buffer(size.value + 1)
260 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
260 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
261 raise ctypes.WinError
261 raise ctypes.WinError
262 return buf.value
262 return buf.value
263
263
264 _signalhandler = []
264 _signalhandler = []
265
265
266 def setsignalhandler():
266 def setsignalhandler():
267 '''Register a termination handler for console events including
267 '''Register a termination handler for console events including
268 CTRL+C. python signal handlers do not work well with socket
268 CTRL+C. python signal handlers do not work well with socket
269 operations.
269 operations.
270 '''
270 '''
271 def handler(event):
271 def handler(event):
272 _kernel32.ExitProcess(1)
272 _kernel32.ExitProcess(1)
273
273
274 if _signalhandler:
274 if _signalhandler:
275 return # already registered
275 return # already registered
276 h = _SIGNAL_HANDLER(handler)
276 h = _SIGNAL_HANDLER(handler)
277 _signalhandler.append(h) # needed to prevent garbage collection
277 _signalhandler.append(h) # needed to prevent garbage collection
278 if not _kernel32.SetConsoleCtrlHandler(h, True):
278 if not _kernel32.SetConsoleCtrlHandler(h, True):
279 raise ctypes.WinError
279 raise ctypes.WinError
280
280
281 def hidewindow():
281 def hidewindow():
282
282
283 def callback(hwnd, pid):
283 def callback(hwnd, pid):
284 wpid = _DWORD()
284 wpid = _DWORD()
285 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
285 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
286 if pid == wpid.value:
286 if pid == wpid.value:
287 _user32.ShowWindow(hwnd, _SW_HIDE)
287 _user32.ShowWindow(hwnd, _SW_HIDE)
288 return False # stop enumerating windows
288 return False # stop enumerating windows
289 return True
289 return True
290
290
291 pid = _kernel32.GetCurrentProcessId()
291 pid = _kernel32.GetCurrentProcessId()
292 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
292 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
293
293
294 def termwidth():
294 def termwidth():
295 # cmd.exe does not handle CR like a unix console, the CR is
295 # cmd.exe does not handle CR like a unix console, the CR is
296 # counted in the line length. On 80 columns consoles, if 80
296 # counted in the line length. On 80 columns consoles, if 80
297 # characters are written, the following CR won't apply on the
297 # characters are written, the following CR won't apply on the
298 # current line but on the new one. Keep room for it.
298 # current line but on the new one. Keep room for it.
299 width = 79
299 width = 79
300 # Query stderr to avoid problems with redirections
300 # Query stderr to avoid problems with redirections
301 screenbuf = _kernel32.GetStdHandle(
301 screenbuf = _kernel32.GetStdHandle(
302 _STD_ERROR_HANDLE) # don't close the handle returned
302 _STD_ERROR_HANDLE) # don't close the handle returned
303 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
303 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
304 return width
304 return width
305 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
305 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
306 if not _kernel32.GetConsoleScreenBufferInfo(
306 if not _kernel32.GetConsoleScreenBufferInfo(
307 screenbuf, ctypes.byref(csbi)):
307 screenbuf, ctypes.byref(csbi)):
308 return width
308 return width
309 width = csbi.srWindow.Right - csbi.srWindow.Left
309 width = csbi.srWindow.Right - csbi.srWindow.Left
310 return width
310 return width
311
311
312 def spawndetached(args):
312 def spawndetached(args):
313 # No standard library function really spawns a fully detached
313 # No standard library function really spawns a fully detached
314 # process under win32 because they allocate pipes or other objects
314 # process under win32 because they allocate pipes or other objects
315 # to handle standard streams communications. Passing these objects
315 # to handle standard streams communications. Passing these objects
316 # to the child process requires handle inheritance to be enabled
316 # to the child process requires handle inheritance to be enabled
317 # which makes really detached processes impossible.
317 # which makes really detached processes impossible.
318 si = _STARTUPINFO()
318 si = _STARTUPINFO()
319 si.cb = ctypes.sizeof(_STARTUPINFO)
319 si.cb = ctypes.sizeof(_STARTUPINFO)
320
320
321 pi = _PROCESS_INFORMATION()
321 pi = _PROCESS_INFORMATION()
322
322
323 env = ''
323 env = ''
324 for k in os.environ:
324 for k in os.environ:
325 env += "%s=%s\0" % (k, os.environ[k])
325 env += "%s=%s\0" % (k, os.environ[k])
326 if not env:
326 if not env:
327 env = '\0'
327 env = '\0'
328 env += '\0'
328 env += '\0'
329
329
330 args = subprocess.list2cmdline(args)
330 args = subprocess.list2cmdline(args)
331 # Not running the command in shell mode makes Python 2.6 hang when
331 # Not running the command in shell mode makes Python 2.6 hang when
332 # writing to hgweb output socket.
332 # writing to hgweb output socket.
333 comspec = os.environ.get("COMSPEC", "cmd.exe")
333 comspec = os.environ.get("COMSPEC", "cmd.exe")
334 args = comspec + " /c " + args
334 args = comspec + " /c " + args
335
335
336 res = _kernel32.CreateProcessA(
336 res = _kernel32.CreateProcessA(
337 None, args, None, None, False, _CREATE_NO_WINDOW,
337 None, args, None, None, False, _CREATE_NO_WINDOW,
338 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
338 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
339 if not res:
339 if not res:
340 raise ctypes.WinError
340 raise ctypes.WinError
341
341
342 return pi.dwProcessId
342 return pi.dwProcessId
343
343
344 def unlink(f):
344 def unlink(f):
345 '''try to implement POSIX' unlink semantics on Windows'''
345 '''try to implement POSIX' unlink semantics on Windows'''
346
346
347 # POSIX allows to unlink and rename open files. Windows has serious
347 # POSIX allows to unlink and rename open files. Windows has serious
348 # problems with doing that:
348 # problems with doing that:
349 # - Calling os.unlink (or os.rename) on a file f fails if f or any
349 # - Calling os.unlink (or os.rename) on a file f fails if f or any
350 # hardlinked copy of f has been opened with Python's open(). There is no
350 # hardlinked copy of f has been opened with Python's open(). There is no
351 # way such a file can be deleted or renamed on Windows (other than
351 # way such a file can be deleted or renamed on Windows (other than
352 # scheduling the delete or rename for the next reboot).
352 # scheduling the delete or rename for the next reboot).
353 # - Calling os.unlink on a file that has been opened with Mercurial's
353 # - Calling os.unlink on a file that has been opened with Mercurial's
354 # posixfile (or comparable methods) will delay the actual deletion of
354 # posixfile (or comparable methods) will delay the actual deletion of
355 # the file for as long as the file is held open. The filename is blocked
355 # the file for as long as the file is held open. The filename is blocked
356 # during that time and cannot be used for recreating a new file under
356 # during that time and cannot be used for recreating a new file under
357 # that same name ("zombie file"). Directories containing such zombie files
357 # that same name ("zombie file"). Directories containing such zombie files
358 # cannot be removed or moved.
358 # cannot be removed or moved.
359 # A file that has been opened with posixfile can be renamed, so we rename
359 # A file that has been opened with posixfile can be renamed, so we rename
360 # f to a random temporary name before calling os.unlink on it. This allows
360 # f to a random temporary name before calling os.unlink on it. This allows
361 # callers to recreate f immediately while having other readers do their
361 # callers to recreate f immediately while having other readers do their
362 # implicit zombie filename blocking on a temporary name.
362 # implicit zombie filename blocking on a temporary name.
363
363
364 for tries in xrange(10):
364 for tries in xrange(10):
365 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
365 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
366 try:
366 try:
367 os.rename(f, temp) # raises OSError EEXIST if temp exists
367 os.rename(f, temp) # raises OSError EEXIST if temp exists
368 break
368 break
369 except OSError, e:
369 except OSError, e:
370 if e.errno != errno.EEXIST:
370 if e.errno != errno.EEXIST:
371 raise
371 raise
372 else:
372 else:
373 raise IOError, (errno.EEXIST, "No usable temporary filename found")
373 raise IOError(errno.EEXIST, "No usable temporary filename found")
374
374
375 try:
375 try:
376 os.unlink(temp)
376 os.unlink(temp)
377 except OSError:
377 except OSError:
378 # The unlink might have failed because the READONLY attribute may heave
378 # The unlink might have failed because the READONLY attribute may heave
379 # been set on the original file. Rename works fine with READONLY set,
379 # been set on the original file. Rename works fine with READONLY set,
380 # but not os.unlink. Reset all attributes and try again.
380 # but not os.unlink. Reset all attributes and try again.
381 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
381 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
382 try:
382 try:
383 os.unlink(temp)
383 os.unlink(temp)
384 except OSError:
384 except OSError:
385 # The unlink might have failed due to some very rude AV-Scanners.
385 # The unlink might have failed due to some very rude AV-Scanners.
386 # Leaking a tempfile is the lesser evil than aborting here and
386 # Leaking a tempfile is the lesser evil than aborting here and
387 # leaving some potentially serious inconsistencies.
387 # leaving some potentially serious inconsistencies.
388 pass
388 pass
389
389
390 def makedir(path, notindexed):
390 def makedir(path, notindexed):
391 os.mkdir(path)
391 os.mkdir(path)
392 if notindexed:
392 if notindexed:
393 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
393 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
General Comments 0
You need to be logged in to leave comments. Login now