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