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