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