--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/win32.py Thu Mar 26 13:54:44 2009 -0500
@@ -0,0 +1,379 @@
+'''
+win32.py - utility functions that use win32 API
+
+Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
+
+This software may be used and distributed according to the terms of
+the GNU General Public License, incorporated herein by reference.
+
+Mark Hammond's win32all package allows better functionality on
+Windows. this module overrides definitions in util.py. if not
+available, import of this module will fail, and generic code will be
+used.
+'''
+
+import win32api
+
+import errno, os, sys, pywintypes, win32con, win32file, win32process
+import cStringIO, winerror
+import osutil
+import util
+from win32com.shell import shell,shellcon
+
+class WinError(Exception):
+ winerror_map = {
+ winerror.ERROR_ACCESS_DENIED: errno.EACCES,
+ winerror.ERROR_ACCOUNT_DISABLED: errno.EACCES,
+ winerror.ERROR_ACCOUNT_RESTRICTION: errno.EACCES,
+ winerror.ERROR_ALREADY_ASSIGNED: errno.EBUSY,
+ winerror.ERROR_ALREADY_EXISTS: errno.EEXIST,
+ winerror.ERROR_ARITHMETIC_OVERFLOW: errno.ERANGE,
+ winerror.ERROR_BAD_COMMAND: errno.EIO,
+ winerror.ERROR_BAD_DEVICE: errno.ENODEV,
+ winerror.ERROR_BAD_DRIVER_LEVEL: errno.ENXIO,
+ winerror.ERROR_BAD_EXE_FORMAT: errno.ENOEXEC,
+ winerror.ERROR_BAD_FORMAT: errno.ENOEXEC,
+ winerror.ERROR_BAD_LENGTH: errno.EINVAL,
+ winerror.ERROR_BAD_PATHNAME: errno.ENOENT,
+ winerror.ERROR_BAD_PIPE: errno.EPIPE,
+ winerror.ERROR_BAD_UNIT: errno.ENODEV,
+ winerror.ERROR_BAD_USERNAME: errno.EINVAL,
+ winerror.ERROR_BROKEN_PIPE: errno.EPIPE,
+ winerror.ERROR_BUFFER_OVERFLOW: errno.ENAMETOOLONG,
+ winerror.ERROR_BUSY: errno.EBUSY,
+ winerror.ERROR_BUSY_DRIVE: errno.EBUSY,
+ winerror.ERROR_CALL_NOT_IMPLEMENTED: errno.ENOSYS,
+ winerror.ERROR_CANNOT_MAKE: errno.EACCES,
+ winerror.ERROR_CANTOPEN: errno.EIO,
+ winerror.ERROR_CANTREAD: errno.EIO,
+ winerror.ERROR_CANTWRITE: errno.EIO,
+ winerror.ERROR_CRC: errno.EIO,
+ winerror.ERROR_CURRENT_DIRECTORY: errno.EACCES,
+ winerror.ERROR_DEVICE_IN_USE: errno.EBUSY,
+ winerror.ERROR_DEV_NOT_EXIST: errno.ENODEV,
+ winerror.ERROR_DIRECTORY: errno.EINVAL,
+ winerror.ERROR_DIR_NOT_EMPTY: errno.ENOTEMPTY,
+ winerror.ERROR_DISK_CHANGE: errno.EIO,
+ winerror.ERROR_DISK_FULL: errno.ENOSPC,
+ winerror.ERROR_DRIVE_LOCKED: errno.EBUSY,
+ winerror.ERROR_ENVVAR_NOT_FOUND: errno.EINVAL,
+ winerror.ERROR_EXE_MARKED_INVALID: errno.ENOEXEC,
+ winerror.ERROR_FILENAME_EXCED_RANGE: errno.ENAMETOOLONG,
+ winerror.ERROR_FILE_EXISTS: errno.EEXIST,
+ winerror.ERROR_FILE_INVALID: errno.ENODEV,
+ winerror.ERROR_FILE_NOT_FOUND: errno.ENOENT,
+ winerror.ERROR_GEN_FAILURE: errno.EIO,
+ winerror.ERROR_HANDLE_DISK_FULL: errno.ENOSPC,
+ winerror.ERROR_INSUFFICIENT_BUFFER: errno.ENOMEM,
+ winerror.ERROR_INVALID_ACCESS: errno.EACCES,
+ winerror.ERROR_INVALID_ADDRESS: errno.EFAULT,
+ winerror.ERROR_INVALID_BLOCK: errno.EFAULT,
+ winerror.ERROR_INVALID_DATA: errno.EINVAL,
+ winerror.ERROR_INVALID_DRIVE: errno.ENODEV,
+ winerror.ERROR_INVALID_EXE_SIGNATURE: errno.ENOEXEC,
+ winerror.ERROR_INVALID_FLAGS: errno.EINVAL,
+ winerror.ERROR_INVALID_FUNCTION: errno.ENOSYS,
+ winerror.ERROR_INVALID_HANDLE: errno.EBADF,
+ winerror.ERROR_INVALID_LOGON_HOURS: errno.EACCES,
+ winerror.ERROR_INVALID_NAME: errno.EINVAL,
+ winerror.ERROR_INVALID_OWNER: errno.EINVAL,
+ winerror.ERROR_INVALID_PARAMETER: errno.EINVAL,
+ winerror.ERROR_INVALID_PASSWORD: errno.EPERM,
+ winerror.ERROR_INVALID_PRIMARY_GROUP: errno.EINVAL,
+ winerror.ERROR_INVALID_SIGNAL_NUMBER: errno.EINVAL,
+ winerror.ERROR_INVALID_TARGET_HANDLE: errno.EIO,
+ winerror.ERROR_INVALID_WORKSTATION: errno.EACCES,
+ winerror.ERROR_IO_DEVICE: errno.EIO,
+ winerror.ERROR_IO_INCOMPLETE: errno.EINTR,
+ winerror.ERROR_LOCKED: errno.EBUSY,
+ winerror.ERROR_LOCK_VIOLATION: errno.EACCES,
+ winerror.ERROR_LOGON_FAILURE: errno.EACCES,
+ winerror.ERROR_MAPPED_ALIGNMENT: errno.EINVAL,
+ winerror.ERROR_META_EXPANSION_TOO_LONG: errno.E2BIG,
+ winerror.ERROR_MORE_DATA: errno.EPIPE,
+ winerror.ERROR_NEGATIVE_SEEK: errno.ESPIPE,
+ winerror.ERROR_NOACCESS: errno.EFAULT,
+ winerror.ERROR_NONE_MAPPED: errno.EINVAL,
+ winerror.ERROR_NOT_ENOUGH_MEMORY: errno.ENOMEM,
+ winerror.ERROR_NOT_READY: errno.EAGAIN,
+ winerror.ERROR_NOT_SAME_DEVICE: errno.EXDEV,
+ winerror.ERROR_NO_DATA: errno.EPIPE,
+ winerror.ERROR_NO_MORE_SEARCH_HANDLES: errno.EIO,
+ winerror.ERROR_NO_PROC_SLOTS: errno.EAGAIN,
+ winerror.ERROR_NO_SUCH_PRIVILEGE: errno.EACCES,
+ winerror.ERROR_OPEN_FAILED: errno.EIO,
+ winerror.ERROR_OPEN_FILES: errno.EBUSY,
+ winerror.ERROR_OPERATION_ABORTED: errno.EINTR,
+ winerror.ERROR_OUTOFMEMORY: errno.ENOMEM,
+ winerror.ERROR_PASSWORD_EXPIRED: errno.EACCES,
+ winerror.ERROR_PATH_BUSY: errno.EBUSY,
+ winerror.ERROR_PATH_NOT_FOUND: errno.ENOENT,
+ winerror.ERROR_PIPE_BUSY: errno.EBUSY,
+ winerror.ERROR_PIPE_CONNECTED: errno.EPIPE,
+ winerror.ERROR_PIPE_LISTENING: errno.EPIPE,
+ winerror.ERROR_PIPE_NOT_CONNECTED: errno.EPIPE,
+ winerror.ERROR_PRIVILEGE_NOT_HELD: errno.EACCES,
+ winerror.ERROR_READ_FAULT: errno.EIO,
+ winerror.ERROR_SEEK: errno.EIO,
+ winerror.ERROR_SEEK_ON_DEVICE: errno.ESPIPE,
+ winerror.ERROR_SHARING_BUFFER_EXCEEDED: errno.ENFILE,
+ winerror.ERROR_SHARING_VIOLATION: errno.EACCES,
+ winerror.ERROR_STACK_OVERFLOW: errno.ENOMEM,
+ winerror.ERROR_SWAPERROR: errno.ENOENT,
+ winerror.ERROR_TOO_MANY_MODULES: errno.EMFILE,
+ winerror.ERROR_TOO_MANY_OPEN_FILES: errno.EMFILE,
+ winerror.ERROR_UNRECOGNIZED_MEDIA: errno.ENXIO,
+ winerror.ERROR_UNRECOGNIZED_VOLUME: errno.ENODEV,
+ winerror.ERROR_WAIT_NO_CHILDREN: errno.ECHILD,
+ winerror.ERROR_WRITE_FAULT: errno.EIO,
+ winerror.ERROR_WRITE_PROTECT: errno.EROFS,
+ }
+
+ def __init__(self, err):
+ self.win_errno, self.win_function, self.win_strerror = err
+ if self.win_strerror.endswith('.'):
+ self.win_strerror = self.win_strerror[:-1]
+
+class WinIOError(WinError, IOError):
+ def __init__(self, err, filename=None):
+ WinError.__init__(self, err)
+ IOError.__init__(self, self.winerror_map.get(self.win_errno, 0),
+ self.win_strerror)
+ self.filename = filename
+
+class WinOSError(WinError, OSError):
+ def __init__(self, err):
+ WinError.__init__(self, err)
+ OSError.__init__(self, self.winerror_map.get(self.win_errno, 0),
+ self.win_strerror)
+
+def os_link(src, dst):
+ try:
+ win32file.CreateHardLink(dst, src)
+ # CreateHardLink sometimes succeeds on mapped drives but
+ # following nlinks() returns 1. Check it now and bail out.
+ if nlinks(src) < 2:
+ try:
+ win32file.DeleteFile(dst)
+ except:
+ pass
+ # Fake hardlinking error
+ raise WinOSError((18, 'CreateHardLink', 'The system cannot '
+ 'move the file to a different disk drive'))
+ except pywintypes.error, details:
+ raise WinOSError(details)
+ except NotImplementedError: # Another fake error win Win98
+ raise WinOSError((18, 'CreateHardLink', 'Hardlinking not supported'))
+
+def nlinks(pathname):
+ """Return number of hardlinks for the given file."""
+ try:
+ fh = win32file.CreateFile(pathname,
+ win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
+ None, win32file.OPEN_EXISTING, 0, None)
+ res = win32file.GetFileInformationByHandle(fh)
+ fh.Close()
+ return res[7]
+ except pywintypes.error:
+ return os.lstat(pathname).st_nlink
+
+def testpid(pid):
+ '''return True if pid is still running or unable to
+ determine, False otherwise'''
+ try:
+ handle = win32api.OpenProcess(
+ win32con.PROCESS_QUERY_INFORMATION, False, pid)
+ if handle:
+ status = win32process.GetExitCodeProcess(handle)
+ return status == win32con.STILL_ACTIVE
+ except pywintypes.error, details:
+ return details[0] != winerror.ERROR_INVALID_PARAMETER
+ return True
+
+def lookup_reg(key, valname=None, scope=None):
+ ''' Look up a key/value name in the Windows registry.
+
+ valname: value name. If unspecified, the default value for the key
+ is used.
+ scope: optionally specify scope for registry lookup, this can be
+ a sequence of scopes to look up in order. Default (CURRENT_USER,
+ LOCAL_MACHINE).
+ '''
+ try:
+ from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
+ QueryValueEx, OpenKey
+ except ImportError:
+ return None
+
+ if scope is None:
+ scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
+ elif not isinstance(scope, (list, tuple)):
+ scope = (scope,)
+ for s in scope:
+ try:
+ val = QueryValueEx(OpenKey(s, key), valname)[0]
+ # never let a Unicode string escape into the wild
+ return util.tolocal(val.encode('UTF-8'))
+ except EnvironmentError:
+ pass
+
+def system_rcpath_win32():
+ '''return default os-specific hgrc search path'''
+ proc = win32api.GetCurrentProcess()
+ try:
+ # This will fail on windows < NT
+ filename = win32process.GetModuleFileNameEx(proc, 0)
+ except:
+ filename = win32api.GetModuleFileName(0)
+ # Use mercurial.ini found in directory with hg.exe
+ progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
+ if os.path.isfile(progrc):
+ return [progrc]
+ # else look for a system rcpath in the registry
+ try:
+ value = win32api.RegQueryValue(
+ win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
+ rcpath = []
+ for p in value.split(os.pathsep):
+ if p.lower().endswith('mercurial.ini'):
+ rcpath.append(p)
+ elif os.path.isdir(p):
+ for f, kind in osutil.listdir(p):
+ if f.endswith('.rc'):
+ rcpath.append(os.path.join(p, f))
+ return rcpath
+ except pywintypes.error:
+ return []
+
+def user_rcpath_win32():
+ '''return os-specific hgrc search path to the user dir'''
+ userdir = os.path.expanduser('~')
+ if sys.getwindowsversion()[3] != 2 and userdir == '~':
+ # We are on win < nt: fetch the APPDATA directory location and use
+ # the parent directory as the user home dir.
+ appdir = shell.SHGetPathFromIDList(
+ shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
+ userdir = os.path.dirname(appdir)
+ return [os.path.join(userdir, 'mercurial.ini'),
+ os.path.join(userdir, '.hgrc')]
+
+class posixfile_nt(object):
+ '''file object with posix-like semantics. on windows, normal
+ files can not be deleted or renamed if they are open. must open
+ with win32file.FILE_SHARE_DELETE. this flag does not exist on
+ windows < nt, so do not use this class there.'''
+
+ # tried to use win32file._open_osfhandle to pass fd to os.fdopen,
+ # but does not work at all. wrap win32 file api instead.
+
+ def __init__(self, name, mode='rb'):
+ self.closed = False
+ self.name = name
+ self.mode = mode
+ access = 0
+ if 'r' in mode or '+' in mode:
+ access |= win32file.GENERIC_READ
+ if 'w' in mode or 'a' in mode or '+' in mode:
+ access |= win32file.GENERIC_WRITE
+ if 'r' in mode:
+ creation = win32file.OPEN_EXISTING
+ elif 'a' in mode:
+ creation = win32file.OPEN_ALWAYS
+ else:
+ creation = win32file.CREATE_ALWAYS
+ try:
+ self.handle = win32file.CreateFile(name,
+ access,
+ win32file.FILE_SHARE_READ |
+ win32file.FILE_SHARE_WRITE |
+ win32file.FILE_SHARE_DELETE,
+ None,
+ creation,
+ win32file.FILE_ATTRIBUTE_NORMAL,
+ 0)
+ except pywintypes.error, err:
+ raise WinIOError(err, name)
+
+ def __iter__(self):
+ for line in self.readlines():
+ yield line
+
+ def read(self, count=-1):
+ try:
+ cs = cStringIO.StringIO()
+ while count:
+ wincount = int(count)
+ if wincount == -1:
+ wincount = 1048576
+ val, data = win32file.ReadFile(self.handle, wincount)
+ if not data: break
+ cs.write(data)
+ if count != -1:
+ count -= len(data)
+ return cs.getvalue()
+ except pywintypes.error, err:
+ raise WinIOError(err)
+
+ def readlines(self, sizehint=None):
+ # splitlines() splits on single '\r' while readlines()
+ # does not. cStringIO has a well behaving readlines() and is fast.
+ return cStringIO.StringIO(self.read()).readlines()
+
+ def write(self, data):
+ try:
+ if 'a' in self.mode:
+ win32file.SetFilePointer(self.handle, 0, win32file.FILE_END)
+ nwrit = 0
+ while nwrit < len(data):
+ val, nwrit = win32file.WriteFile(self.handle, data)
+ data = data[nwrit:]
+ except pywintypes.error, err:
+ raise WinIOError(err)
+
+ def writelines(self, sequence):
+ for s in sequence:
+ self.write(s)
+
+ def seek(self, pos, whence=0):
+ try:
+ win32file.SetFilePointer(self.handle, int(pos), whence)
+ except pywintypes.error, err:
+ raise WinIOError(err)
+
+ def tell(self):
+ try:
+ return win32file.SetFilePointer(self.handle, 0,
+ win32file.FILE_CURRENT)
+ except pywintypes.error, err:
+ raise WinIOError(err)
+
+ def close(self):
+ if not self.closed:
+ self.handle = None
+ self.closed = True
+
+ def flush(self):
+ # we have no application-level buffering
+ pass
+
+ def truncate(self, pos=0):
+ try:
+ win32file.SetFilePointer(self.handle, int(pos),
+ win32file.FILE_BEGIN)
+ win32file.SetEndOfFile(self.handle)
+ except pywintypes.error, err:
+ raise WinIOError(err)
+
+def getuser():
+ '''return name of current user'''
+ return win32api.GetUserName()
+
+def set_signal_handler_win32():
+ """Register a termination handler for console events including
+ CTRL+C. python signal handlers do not work well with socket
+ operations.
+ """
+ def handler(event):
+ win32process.ExitProcess(1)
+ win32api.SetConsoleCtrlHandler(handler)
+