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