##// END OF EJS Templates
util: disinfect lookup_reg strings (issue1126)...
Matt Mackall -
r6880:892806b3 default
parent child Browse files
Show More
@@ -1,371 +1,367
1 1 # util_win32.py - utility functions that use win32 API
2 2 #
3 3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of
7 7 # the GNU General Public License, incorporated herein by reference.
8 8
9 9 # Mark Hammond's win32all package allows better functionality on
10 10 # Windows. this module overrides definitions in util.py. if not
11 11 # available, import of this module will fail, and generic code will be
12 12 # used.
13 13
14 14 import win32api
15 15
16 16 import errno, os, sys, pywintypes, win32con, win32file, win32process
17 17 import cStringIO, winerror
18 18 import osutil
19 19 from win32com.shell import shell,shellcon
20 20
21 21 class WinError:
22 22 winerror_map = {
23 23 winerror.ERROR_ACCESS_DENIED: errno.EACCES,
24 24 winerror.ERROR_ACCOUNT_DISABLED: errno.EACCES,
25 25 winerror.ERROR_ACCOUNT_RESTRICTION: errno.EACCES,
26 26 winerror.ERROR_ALREADY_ASSIGNED: errno.EBUSY,
27 27 winerror.ERROR_ALREADY_EXISTS: errno.EEXIST,
28 28 winerror.ERROR_ARITHMETIC_OVERFLOW: errno.ERANGE,
29 29 winerror.ERROR_BAD_COMMAND: errno.EIO,
30 30 winerror.ERROR_BAD_DEVICE: errno.ENODEV,
31 31 winerror.ERROR_BAD_DRIVER_LEVEL: errno.ENXIO,
32 32 winerror.ERROR_BAD_EXE_FORMAT: errno.ENOEXEC,
33 33 winerror.ERROR_BAD_FORMAT: errno.ENOEXEC,
34 34 winerror.ERROR_BAD_LENGTH: errno.EINVAL,
35 35 winerror.ERROR_BAD_PATHNAME: errno.ENOENT,
36 36 winerror.ERROR_BAD_PIPE: errno.EPIPE,
37 37 winerror.ERROR_BAD_UNIT: errno.ENODEV,
38 38 winerror.ERROR_BAD_USERNAME: errno.EINVAL,
39 39 winerror.ERROR_BROKEN_PIPE: errno.EPIPE,
40 40 winerror.ERROR_BUFFER_OVERFLOW: errno.ENAMETOOLONG,
41 41 winerror.ERROR_BUSY: errno.EBUSY,
42 42 winerror.ERROR_BUSY_DRIVE: errno.EBUSY,
43 43 winerror.ERROR_CALL_NOT_IMPLEMENTED: errno.ENOSYS,
44 44 winerror.ERROR_CANNOT_MAKE: errno.EACCES,
45 45 winerror.ERROR_CANTOPEN: errno.EIO,
46 46 winerror.ERROR_CANTREAD: errno.EIO,
47 47 winerror.ERROR_CANTWRITE: errno.EIO,
48 48 winerror.ERROR_CRC: errno.EIO,
49 49 winerror.ERROR_CURRENT_DIRECTORY: errno.EACCES,
50 50 winerror.ERROR_DEVICE_IN_USE: errno.EBUSY,
51 51 winerror.ERROR_DEV_NOT_EXIST: errno.ENODEV,
52 52 winerror.ERROR_DIRECTORY: errno.EINVAL,
53 53 winerror.ERROR_DIR_NOT_EMPTY: errno.ENOTEMPTY,
54 54 winerror.ERROR_DISK_CHANGE: errno.EIO,
55 55 winerror.ERROR_DISK_FULL: errno.ENOSPC,
56 56 winerror.ERROR_DRIVE_LOCKED: errno.EBUSY,
57 57 winerror.ERROR_ENVVAR_NOT_FOUND: errno.EINVAL,
58 58 winerror.ERROR_EXE_MARKED_INVALID: errno.ENOEXEC,
59 59 winerror.ERROR_FILENAME_EXCED_RANGE: errno.ENAMETOOLONG,
60 60 winerror.ERROR_FILE_EXISTS: errno.EEXIST,
61 61 winerror.ERROR_FILE_INVALID: errno.ENODEV,
62 62 winerror.ERROR_FILE_NOT_FOUND: errno.ENOENT,
63 63 winerror.ERROR_GEN_FAILURE: errno.EIO,
64 64 winerror.ERROR_HANDLE_DISK_FULL: errno.ENOSPC,
65 65 winerror.ERROR_INSUFFICIENT_BUFFER: errno.ENOMEM,
66 66 winerror.ERROR_INVALID_ACCESS: errno.EACCES,
67 67 winerror.ERROR_INVALID_ADDRESS: errno.EFAULT,
68 68 winerror.ERROR_INVALID_BLOCK: errno.EFAULT,
69 69 winerror.ERROR_INVALID_DATA: errno.EINVAL,
70 70 winerror.ERROR_INVALID_DRIVE: errno.ENODEV,
71 71 winerror.ERROR_INVALID_EXE_SIGNATURE: errno.ENOEXEC,
72 72 winerror.ERROR_INVALID_FLAGS: errno.EINVAL,
73 73 winerror.ERROR_INVALID_FUNCTION: errno.ENOSYS,
74 74 winerror.ERROR_INVALID_HANDLE: errno.EBADF,
75 75 winerror.ERROR_INVALID_LOGON_HOURS: errno.EACCES,
76 76 winerror.ERROR_INVALID_NAME: errno.EINVAL,
77 77 winerror.ERROR_INVALID_OWNER: errno.EINVAL,
78 78 winerror.ERROR_INVALID_PARAMETER: errno.EINVAL,
79 79 winerror.ERROR_INVALID_PASSWORD: errno.EPERM,
80 80 winerror.ERROR_INVALID_PRIMARY_GROUP: errno.EINVAL,
81 81 winerror.ERROR_INVALID_SIGNAL_NUMBER: errno.EINVAL,
82 82 winerror.ERROR_INVALID_TARGET_HANDLE: errno.EIO,
83 83 winerror.ERROR_INVALID_WORKSTATION: errno.EACCES,
84 84 winerror.ERROR_IO_DEVICE: errno.EIO,
85 85 winerror.ERROR_IO_INCOMPLETE: errno.EINTR,
86 86 winerror.ERROR_LOCKED: errno.EBUSY,
87 87 winerror.ERROR_LOCK_VIOLATION: errno.EACCES,
88 88 winerror.ERROR_LOGON_FAILURE: errno.EACCES,
89 89 winerror.ERROR_MAPPED_ALIGNMENT: errno.EINVAL,
90 90 winerror.ERROR_META_EXPANSION_TOO_LONG: errno.E2BIG,
91 91 winerror.ERROR_MORE_DATA: errno.EPIPE,
92 92 winerror.ERROR_NEGATIVE_SEEK: errno.ESPIPE,
93 93 winerror.ERROR_NOACCESS: errno.EFAULT,
94 94 winerror.ERROR_NONE_MAPPED: errno.EINVAL,
95 95 winerror.ERROR_NOT_ENOUGH_MEMORY: errno.ENOMEM,
96 96 winerror.ERROR_NOT_READY: errno.EAGAIN,
97 97 winerror.ERROR_NOT_SAME_DEVICE: errno.EXDEV,
98 98 winerror.ERROR_NO_DATA: errno.EPIPE,
99 99 winerror.ERROR_NO_MORE_SEARCH_HANDLES: errno.EIO,
100 100 winerror.ERROR_NO_PROC_SLOTS: errno.EAGAIN,
101 101 winerror.ERROR_NO_SUCH_PRIVILEGE: errno.EACCES,
102 102 winerror.ERROR_OPEN_FAILED: errno.EIO,
103 103 winerror.ERROR_OPEN_FILES: errno.EBUSY,
104 104 winerror.ERROR_OPERATION_ABORTED: errno.EINTR,
105 105 winerror.ERROR_OUTOFMEMORY: errno.ENOMEM,
106 106 winerror.ERROR_PASSWORD_EXPIRED: errno.EACCES,
107 107 winerror.ERROR_PATH_BUSY: errno.EBUSY,
108 108 winerror.ERROR_PATH_NOT_FOUND: errno.ENOENT,
109 109 winerror.ERROR_PIPE_BUSY: errno.EBUSY,
110 110 winerror.ERROR_PIPE_CONNECTED: errno.EPIPE,
111 111 winerror.ERROR_PIPE_LISTENING: errno.EPIPE,
112 112 winerror.ERROR_PIPE_NOT_CONNECTED: errno.EPIPE,
113 113 winerror.ERROR_PRIVILEGE_NOT_HELD: errno.EACCES,
114 114 winerror.ERROR_READ_FAULT: errno.EIO,
115 115 winerror.ERROR_SEEK: errno.EIO,
116 116 winerror.ERROR_SEEK_ON_DEVICE: errno.ESPIPE,
117 117 winerror.ERROR_SHARING_BUFFER_EXCEEDED: errno.ENFILE,
118 118 winerror.ERROR_SHARING_VIOLATION: errno.EACCES,
119 119 winerror.ERROR_STACK_OVERFLOW: errno.ENOMEM,
120 120 winerror.ERROR_SWAPERROR: errno.ENOENT,
121 121 winerror.ERROR_TOO_MANY_MODULES: errno.EMFILE,
122 122 winerror.ERROR_TOO_MANY_OPEN_FILES: errno.EMFILE,
123 123 winerror.ERROR_UNRECOGNIZED_MEDIA: errno.ENXIO,
124 124 winerror.ERROR_UNRECOGNIZED_VOLUME: errno.ENODEV,
125 125 winerror.ERROR_WAIT_NO_CHILDREN: errno.ECHILD,
126 126 winerror.ERROR_WRITE_FAULT: errno.EIO,
127 127 winerror.ERROR_WRITE_PROTECT: errno.EROFS,
128 128 }
129 129
130 130 def __init__(self, err):
131 131 self.win_errno, self.win_function, self.win_strerror = err
132 132 if self.win_strerror.endswith('.'):
133 133 self.win_strerror = self.win_strerror[:-1]
134 134
135 135 class WinIOError(WinError, IOError):
136 136 def __init__(self, err, filename=None):
137 137 WinError.__init__(self, err)
138 138 IOError.__init__(self, self.winerror_map.get(self.win_errno, 0),
139 139 self.win_strerror)
140 140 self.filename = filename
141 141
142 142 class WinOSError(WinError, OSError):
143 143 def __init__(self, err):
144 144 WinError.__init__(self, err)
145 145 OSError.__init__(self, self.winerror_map.get(self.win_errno, 0),
146 146 self.win_strerror)
147 147
148 148 def os_link(src, dst):
149 149 try:
150 150 win32file.CreateHardLink(dst, src)
151 151 # CreateHardLink sometimes succeeds on mapped drives but
152 152 # following nlinks() returns 1. Check it now and bail out.
153 153 if nlinks(src) < 2:
154 154 try:
155 155 win32file.DeleteFile(dst)
156 156 except:
157 157 pass
158 158 # Fake hardlinking error
159 159 raise WinOSError((18, 'CreateHardLink', 'The system cannot '
160 160 'move the file to a different disk drive'))
161 161 except pywintypes.error, details:
162 162 raise WinOSError(details)
163 163
164 164 def nlinks(pathname):
165 165 """Return number of hardlinks for the given file."""
166 166 try:
167 167 fh = win32file.CreateFile(pathname,
168 168 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
169 169 None, win32file.OPEN_EXISTING, 0, None)
170 170 res = win32file.GetFileInformationByHandle(fh)
171 171 fh.Close()
172 172 return res[7]
173 173 except pywintypes.error:
174 174 return os.lstat(pathname).st_nlink
175 175
176 176 def testpid(pid):
177 177 '''return True if pid is still running or unable to
178 178 determine, False otherwise'''
179 179 try:
180 180 handle = win32api.OpenProcess(
181 181 win32con.PROCESS_QUERY_INFORMATION, False, pid)
182 182 if handle:
183 183 status = win32process.GetExitCodeProcess(handle)
184 184 return status == win32con.STILL_ACTIVE
185 185 except pywintypes.error, details:
186 186 return details[0] != winerror.ERROR_INVALID_PARAMETER
187 187 return True
188 188
189 189 def lookup_reg(key, valname=None, scope=None):
190 190 ''' Look up a key/value name in the Windows registry.
191 191
192 192 valname: value name. If unspecified, the default value for the key
193 193 is used.
194 194 scope: optionally specify scope for registry lookup, this can be
195 195 a sequence of scopes to look up in order. Default (CURRENT_USER,
196 196 LOCAL_MACHINE).
197 197 '''
198 198 try:
199 199 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
200 200 QueryValueEx, OpenKey
201 201 except ImportError:
202 202 return None
203 203
204 def query_val(scope, key, valname):
205 try:
206 keyhandle = OpenKey(scope, key)
207 return QueryValueEx(keyhandle, valname)[0]
208 except EnvironmentError:
209 return None
210
211 204 if scope is None:
212 205 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
213 206 elif not isinstance(scope, (list, tuple)):
214 207 scope = (scope,)
215 208 for s in scope:
216 val = query_val(s, key, valname)
217 if val is not None:
218 return val
209 try:
210 val = QueryValueEx(OpenKey(scope, key), valname)[0]
211 # never let a Unicode string escape into the wild
212 return util.tolocal(val.encode('UTF-8'))
213 except EnvironmentError:
214 pass
219 215
220 216 def system_rcpath_win32():
221 217 '''return default os-specific hgrc search path'''
222 218 proc = win32api.GetCurrentProcess()
223 219 try:
224 220 # This will fail on windows < NT
225 221 filename = win32process.GetModuleFileNameEx(proc, 0)
226 222 except:
227 223 filename = win32api.GetModuleFileName(0)
228 224 # Use mercurial.ini found in directory with hg.exe
229 225 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
230 226 if os.path.isfile(progrc):
231 227 return [progrc]
232 228 # else look for a system rcpath in the registry
233 229 try:
234 230 value = win32api.RegQueryValue(
235 231 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
236 232 rcpath = []
237 233 for p in value.split(os.pathsep):
238 234 if p.lower().endswith('mercurial.ini'):
239 235 rcpath.append(p)
240 236 elif os.path.isdir(p):
241 237 for f, kind in osutil.listdir(p):
242 238 if f.endswith('.rc'):
243 239 rcpath.append(os.path.join(p, f))
244 240 return rcpath
245 241 except pywintypes.error:
246 242 return []
247 243
248 244 def user_rcpath_win32():
249 245 '''return os-specific hgrc search path to the user dir'''
250 246 userdir = os.path.expanduser('~')
251 247 if sys.getwindowsversion() != 2 and userdir == '~':
252 248 # We are on win < nt: fetch the APPDATA directory location and use
253 249 # the parent directory as the user home dir.
254 250 appdir = shell.SHGetPathFromIDList(
255 251 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
256 252 userdir = os.path.dirname(appdir)
257 253 return [os.path.join(userdir, 'mercurial.ini'),
258 254 os.path.join(userdir, '.hgrc')]
259 255
260 256 class posixfile_nt(object):
261 257 '''file object with posix-like semantics. on windows, normal
262 258 files can not be deleted or renamed if they are open. must open
263 259 with win32file.FILE_SHARE_DELETE. this flag does not exist on
264 260 windows < nt, so do not use this class there.'''
265 261
266 262 # tried to use win32file._open_osfhandle to pass fd to os.fdopen,
267 263 # but does not work at all. wrap win32 file api instead.
268 264
269 265 def __init__(self, name, mode='rb'):
270 266 self.closed = False
271 267 self.name = name
272 268 self.mode = mode
273 269 access = 0
274 270 if 'r' in mode or '+' in mode:
275 271 access |= win32file.GENERIC_READ
276 272 if 'w' in mode or 'a' in mode or '+' in mode:
277 273 access |= win32file.GENERIC_WRITE
278 274 if 'r' in mode:
279 275 creation = win32file.OPEN_EXISTING
280 276 elif 'a' in mode:
281 277 creation = win32file.OPEN_ALWAYS
282 278 else:
283 279 creation = win32file.CREATE_ALWAYS
284 280 try:
285 281 self.handle = win32file.CreateFile(name,
286 282 access,
287 283 win32file.FILE_SHARE_READ |
288 284 win32file.FILE_SHARE_WRITE |
289 285 win32file.FILE_SHARE_DELETE,
290 286 None,
291 287 creation,
292 288 win32file.FILE_ATTRIBUTE_NORMAL,
293 289 0)
294 290 except pywintypes.error, err:
295 291 raise WinIOError(err, name)
296 292
297 293 def __iter__(self):
298 294 for line in self.read().splitlines(True):
299 295 yield line
300 296
301 297 def read(self, count=-1):
302 298 try:
303 299 cs = cStringIO.StringIO()
304 300 while count:
305 301 wincount = int(count)
306 302 if wincount == -1:
307 303 wincount = 1048576
308 304 val, data = win32file.ReadFile(self.handle, wincount)
309 305 if not data: break
310 306 cs.write(data)
311 307 if count != -1:
312 308 count -= len(data)
313 309 return cs.getvalue()
314 310 except pywintypes.error, err:
315 311 raise WinIOError(err)
316 312
317 313 def write(self, data):
318 314 try:
319 315 if 'a' in self.mode:
320 316 win32file.SetFilePointer(self.handle, 0, win32file.FILE_END)
321 317 nwrit = 0
322 318 while nwrit < len(data):
323 319 val, nwrit = win32file.WriteFile(self.handle, data)
324 320 data = data[nwrit:]
325 321 except pywintypes.error, err:
326 322 raise WinIOError(err)
327 323
328 324 def writelines(self, sequence):
329 325 for s in sequence:
330 326 self.write(s)
331 327
332 328 def seek(self, pos, whence=0):
333 329 try:
334 330 win32file.SetFilePointer(self.handle, int(pos), whence)
335 331 except pywintypes.error, err:
336 332 raise WinIOError(err)
337 333
338 334 def tell(self):
339 335 try:
340 336 return win32file.SetFilePointer(self.handle, 0,
341 337 win32file.FILE_CURRENT)
342 338 except pywintypes.error, err:
343 339 raise WinIOError(err)
344 340
345 341 def close(self):
346 342 if not self.closed:
347 343 self.handle = None
348 344 self.closed = True
349 345
350 346 def flush(self):
351 347 # we have no application-level buffering
352 348 pass
353 349
354 350 def truncate(self, pos=0):
355 351 try:
356 352 win32file.SetFilePointer(self.handle, int(pos),
357 353 win32file.FILE_BEGIN)
358 354 win32file.SetEndOfFile(self.handle)
359 355 except pywintypes.error, err:
360 356 raise WinIOError(err)
361 357
362 358 getuser_fallback = win32api.GetUserName
363 359
364 360 def set_signal_handler_win32():
365 361 """Register a termination handler for console events including
366 362 CTRL+C. python signal handlers do not work well with socket
367 363 operations.
368 364 """
369 365 def handler(event):
370 366 win32process.ExitProcess(1)
371 367 win32api.SetConsoleCtrlHandler(handler)
General Comments 0
You need to be logged in to leave comments. Login now