changeset 7890:e710f0f592b2

util: split out posix, windows, and win32 modules
author Matt Mackall <mpm@selenic.com>
date Thu, 26 Mar 2009 13:54:44 -0500
parents 5ac1a72e5b74
children 3e0c28145e6a
files mercurial/posix.py mercurial/store.py mercurial/util.py mercurial/util_win32.py mercurial/win32.py mercurial/windows.py
diffstat 6 files changed, 892 insertions(+), 869 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/posix.py	Thu Mar 26 13:54:44 2009 -0500
@@ -0,0 +1,222 @@
+"""
+posix.py - Posix utility function implementations for Mercurial
+
+ 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 version 2, incorporated herein by
+reference.
+"""
+
+from i18n import _
+import os, sys, osutil, errno, stat, getpass
+
+posixfile = file
+nulldev = '/dev/null'
+normpath = os.path.normpath
+samestat = os.path.samestat
+
+umask = os.umask(0)
+os.umask(umask)
+
+def openhardlinks():
+    '''return true if it is safe to hold open file handles to hardlinks'''
+    return True
+
+def rcfiles(path):
+    rcs = [os.path.join(path, 'hgrc')]
+    rcdir = os.path.join(path, 'hgrc.d')
+    try:
+        rcs.extend([os.path.join(rcdir, f)
+                    for f, kind in osutil.listdir(rcdir)
+                    if f.endswith(".rc")])
+    except OSError:
+        pass
+    return rcs
+
+def system_rcpath():
+    path = []
+    # old mod_python does not set sys.argv
+    if len(getattr(sys, 'argv', [])) > 0:
+        path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
+                              '/../etc/mercurial'))
+    path.extend(rcfiles('/etc/mercurial'))
+    return path
+
+def user_rcpath():
+    return [os.path.expanduser('~/.hgrc')]
+
+def parse_patch_output(output_line):
+    """parses the output produced by patch and returns the file name"""
+    pf = output_line[14:]
+    if os.sys.platform == 'OpenVMS':
+        if pf[0] == '`':
+            pf = pf[1:-1] # Remove the quotes
+    else:
+       if pf.startswith("'") and pf.endswith("'") and " " in pf:
+            pf = pf[1:-1] # Remove the quotes
+    return pf
+
+def sshargs(sshcmd, host, user, port):
+    '''Build argument list for ssh'''
+    args = user and ("%s@%s" % (user, host)) or host
+    return port and ("%s -p %s" % (args, port)) or args
+
+def is_exec(f):
+    """check whether a file is executable"""
+    return (os.lstat(f).st_mode & 0100 != 0)
+
+def set_flags(f, l, x):
+    s = os.lstat(f).st_mode
+    if l:
+        if not stat.S_ISLNK(s):
+            # switch file to link
+            data = file(f).read()
+            os.unlink(f)
+            try:
+                os.symlink(data, f)
+            except:
+                # failed to make a link, rewrite file
+                file(f, "w").write(data)
+        # no chmod needed at this point
+        return
+    if stat.S_ISLNK(s):
+        # switch link to file
+        data = os.readlink(f)
+        os.unlink(f)
+        file(f, "w").write(data)
+        s = 0666 & ~umask # avoid restatting for chmod
+
+    sx = s & 0100
+    if x and not sx:
+        # Turn on +x for every +r bit when making a file executable
+        # and obey umask.
+        os.chmod(f, s | (s & 0444) >> 2 & ~umask)
+    elif not x and sx:
+        # Turn off all +x bits
+        os.chmod(f, s & 0666)
+
+def set_binary(fd):
+    pass
+
+def pconvert(path):
+    return path
+
+def localpath(path):
+    return path
+
+def shellquote(s):
+    if os.sys.platform == 'OpenVMS':
+        return '"%s"' % s
+    else:
+        return "'%s'" % s.replace("'", "'\\''")
+
+def quotecommand(cmd):
+    return cmd
+
+def popen(command, mode='r'):
+    return os.popen(command, mode)
+
+def testpid(pid):
+    '''return False if pid dead, True if running or not sure'''
+    if os.sys.platform == 'OpenVMS':
+        return True
+    try:
+        os.kill(pid, 0)
+        return True
+    except OSError, inst:
+        return inst.errno != errno.ESRCH
+
+def explain_exit(code):
+    """return a 2-tuple (desc, code) describing a process's status"""
+    if os.WIFEXITED(code):
+        val = os.WEXITSTATUS(code)
+        return _("exited with status %d") % val, val
+    elif os.WIFSIGNALED(code):
+        val = os.WTERMSIG(code)
+        return _("killed by signal %d") % val, val
+    elif os.WIFSTOPPED(code):
+        val = os.WSTOPSIG(code)
+        return _("stopped by signal %d") % val, val
+    raise ValueError(_("invalid exit code"))
+
+def isowner(fp, st=None):
+    """Return True if the file object f belongs to the current user.
+
+    The return value of a util.fstat(f) may be passed as the st argument.
+    """
+    if st is None:
+        st = fstat(fp)
+    return st.st_uid == os.getuid()
+
+def find_exe(command):
+    '''Find executable for command searching like which does.
+    If command is a basename then PATH is searched for command.
+    PATH isn't searched if command is an absolute or relative path.
+    If command isn't found None is returned.'''
+    if sys.platform == 'OpenVMS':
+        return command
+
+    def findexisting(executable):
+        'Will return executable if existing file'
+        if os.path.exists(executable):
+            return executable
+        return None
+
+    if os.sep in command:
+        return findexisting(command)
+
+    for path in os.environ.get('PATH', '').split(os.pathsep):
+        executable = findexisting(os.path.join(path, command))
+        if executable is not None:
+            return executable
+    return None
+
+def set_signal_handler():
+    pass
+
+def statfiles(files):
+    'Stat each file in files and yield stat or None if file does not exist.'
+    lstat = os.lstat
+    for nf in files:
+        try:
+            st = lstat(nf)
+        except OSError, err:
+            if err.errno not in (errno.ENOENT, errno.ENOTDIR):
+                raise
+            st = None
+        yield st
+
+def getuser():
+    '''return name of current user'''
+    return getpass.getuser()
+
+def expand_glob(pats):
+    '''On Windows, expand the implicit globs in a list of patterns'''
+    return list(pats)
+
+def username(uid=None):
+    """Return the name of the user with the given uid.
+
+    If uid is None, return the name of the current user."""
+
+    if uid is None:
+        uid = os.getuid()
+    try:
+        return pwd.getpwuid(uid)[0]
+    except KeyError:
+        return str(uid)
+
+def groupname(gid=None):
+    """Return the name of the group with the given gid.
+
+    If gid is None, return the name of the current group."""
+
+    if gid is None:
+        gid = os.getgid()
+    try:
+        return grp.getgrgid(gid)[0]
+    except KeyError:
+        return str(gid)
+
+
--- a/mercurial/store.py	Sat Mar 14 10:46:48 2009 -0400
+++ b/mercurial/store.py	Thu Mar 26 13:54:44 2009 -0500
@@ -136,7 +136,7 @@
         # files in .hg/ will be created using this mode
         mode = os.stat(path).st_mode
             # avoid some useless chmods
-        if (0777 & ~util._umask) == (0777 & mode):
+        if (0777 & ~util.umask) == (0777 & mode):
             mode = None
     except OSError:
         mode = None
--- a/mercurial/util.py	Sat Mar 14 10:46:48 2009 -0400
+++ b/mercurial/util.py	Thu Mar 26 13:54:44 2009 -0500
@@ -13,7 +13,7 @@
 """
 
 from i18n import _
-import cStringIO, errno, getpass, re, shutil, sys, tempfile, traceback, error
+import cStringIO, errno, re, shutil, sys, tempfile, traceback, error
 import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil
 import imp, unicodedata
 
@@ -339,22 +339,6 @@
 def always(fn): return True
 def never(fn): return False
 
-def expand_glob(pats):
-    '''On Windows, expand the implicit globs in a list of patterns'''
-    if os.name != 'nt':
-        return list(pats)
-    ret = []
-    for p in pats:
-        kind, name = patkind(p, None)
-        if kind is None:
-            globbed = glob.glob(name)
-            if globbed:
-                ret.extend(globbed)
-                continue
-            # if we couldn't expand the glob, just keep it around
-        ret.append(p)
-    return ret
-
 def patkind(name, default):
     """Split a string into an optional pattern kind prefix and the
     actual pattern."""
@@ -858,12 +842,32 @@
         # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
         self.auditeddir.update(prefixes)
 
-def _makelock_file(info, pathname):
+if os.name == 'nt':
+    from windows import *
+else:
+    from posix import *
+
+def makelock(info, pathname):
+    try:
+        return os.symlink(info, pathname)
+    except OSError, why:
+        if why.errno == errno.EEXIST:
+            raise
+    except AttributeError: # no symlink in os
+        pass
+
     ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
     os.write(ld, info)
     os.close(ld)
 
-def _readlock_file(pathname):
+def readlock(pathname):
+    try:
+        return os.readlink(pathname)
+    except OSError, why:
+        if why.errno not in (errno.EINVAL, errno.ENOSYS):
+            raise
+    except AttributeError: # no symlink in os
+        pass
     return posixfile(pathname).read()
 
 def nlinks(pathname):
@@ -883,103 +887,6 @@
     except AttributeError:
         return os.stat(fp.name)
 
-posixfile = file
-
-def openhardlinks():
-    '''return true if it is safe to hold open file handles to hardlinks'''
-    return True
-
-def _statfiles(files):
-    'Stat each file in files and yield stat or None if file does not exist.'
-    lstat = os.lstat
-    for nf in files:
-        try:
-            st = lstat(nf)
-        except OSError, err:
-            if err.errno not in (errno.ENOENT, errno.ENOTDIR):
-                raise
-            st = None
-        yield st
-
-def _statfiles_clustered(files):
-    '''Stat each file in files and yield stat or None if file does not exist.
-    Cluster and cache stat per directory to minimize number of OS stat calls.'''
-    ncase = os.path.normcase
-    sep   = os.sep
-    dircache = {} # dirname -> filename -> status | None if file does not exist
-    for nf in files:
-        nf  = ncase(nf)
-        pos = nf.rfind(sep)
-        if pos == -1:
-            dir, base = '.', nf
-        else:
-            dir, base = nf[:pos+1], nf[pos+1:]
-        cache = dircache.get(dir, None)
-        if cache is None:
-            try:
-                dmap = dict([(ncase(n), s)
-                    for n, k, s in osutil.listdir(dir, True)])
-            except OSError, err:
-                # handle directory not found in Python version prior to 2.5
-                # Python <= 2.4 returns native Windows code 3 in errno
-                # Python >= 2.5 returns ENOENT and adds winerror field
-                # EINVAL is raised if dir is not a directory.
-                if err.errno not in (3, errno.ENOENT, errno.EINVAL,
-                                     errno.ENOTDIR):
-                    raise
-                dmap = {}
-            cache = dircache.setdefault(dir, dmap)
-        yield cache.get(base, None)
-
-if sys.platform == 'win32':
-    statfiles = _statfiles_clustered
-else:
-    statfiles = _statfiles
-
-getuser_fallback = None
-
-def getuser():
-    '''return name of current user'''
-    try:
-        return getpass.getuser()
-    except ImportError:
-        # import of pwd will fail on windows - try fallback
-        if getuser_fallback:
-            return getuser_fallback()
-    # raised if win32api not available
-    raise Abort(_('user name not available - set USERNAME '
-                  'environment variable'))
-
-def username(uid=None):
-    """Return the name of the user with the given uid.
-
-    If uid is None, return the name of the current user."""
-    try:
-        import pwd
-        if uid is None:
-            uid = os.getuid()
-        try:
-            return pwd.getpwuid(uid)[0]
-        except KeyError:
-            return str(uid)
-    except ImportError:
-        return None
-
-def groupname(gid=None):
-    """Return the name of the group with the given gid.
-
-    If gid is None, return the name of the current group."""
-    try:
-        import grp
-        if gid is None:
-            gid = os.getgid()
-        try:
-            return grp.getgrgid(gid)[0]
-        except KeyError:
-            return str(gid)
-    except ImportError:
-        return None
-
 # File system features
 
 def checkcase(path):
@@ -1088,9 +995,6 @@
     except (OSError, AttributeError):
         return False
 
-_umask = os.umask(0)
-os.umask(_umask)
-
 def needbinarypatch():
     """return True if patches should be applied in binary mode by default."""
     return os.name == 'nt'
@@ -1114,379 +1018,6 @@
 def lookup_reg(key, name=None, scope=None):
     return None
 
-# Platform specific variants
-if os.name == 'nt':
-    import msvcrt
-    nulldev = 'NUL:'
-
-    class winstdout:
-        '''stdout on windows misbehaves if sent through a pipe'''
-
-        def __init__(self, fp):
-            self.fp = fp
-
-        def __getattr__(self, key):
-            return getattr(self.fp, key)
-
-        def close(self):
-            try:
-                self.fp.close()
-            except: pass
-
-        def write(self, s):
-            try:
-                # This is workaround for "Not enough space" error on
-                # writing large size of data to console.
-                limit = 16000
-                l = len(s)
-                start = 0
-                while start < l:
-                    end = start + limit
-                    self.fp.write(s[start:end])
-                    start = end
-            except IOError, inst:
-                if inst.errno != 0: raise
-                self.close()
-                raise IOError(errno.EPIPE, 'Broken pipe')
-
-        def flush(self):
-            try:
-                return self.fp.flush()
-            except IOError, inst:
-                if inst.errno != errno.EINVAL: raise
-                self.close()
-                raise IOError(errno.EPIPE, 'Broken pipe')
-
-    sys.stdout = winstdout(sys.stdout)
-
-    def _is_win_9x():
-        '''return true if run on windows 95, 98 or me.'''
-        try:
-            return sys.getwindowsversion()[3] == 1
-        except AttributeError:
-            return 'command' in os.environ.get('comspec', '')
-
-    def openhardlinks():
-        return not _is_win_9x and "win32api" in locals()
-
-    def system_rcpath():
-        try:
-            return system_rcpath_win32()
-        except:
-            return [r'c:\mercurial\mercurial.ini']
-
-    def user_rcpath():
-        '''return os-specific hgrc search path to the user dir'''
-        try:
-            path = user_rcpath_win32()
-        except:
-            home = os.path.expanduser('~')
-            path = [os.path.join(home, 'mercurial.ini'),
-                    os.path.join(home, '.hgrc')]
-        userprofile = os.environ.get('USERPROFILE')
-        if userprofile:
-            path.append(os.path.join(userprofile, 'mercurial.ini'))
-            path.append(os.path.join(userprofile, '.hgrc'))
-        return path
-
-    def parse_patch_output(output_line):
-        """parses the output produced by patch and returns the file name"""
-        pf = output_line[14:]
-        if pf[0] == '`':
-            pf = pf[1:-1] # Remove the quotes
-        return pf
-
-    def sshargs(sshcmd, host, user, port):
-        '''Build argument list for ssh or Plink'''
-        pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
-        args = user and ("%s@%s" % (user, host)) or host
-        return port and ("%s %s %s" % (args, pflag, port)) or args
-
-    def testpid(pid):
-        '''return False if pid dead, True if running or not known'''
-        return True
-
-    def set_flags(f, l, x):
-        pass
-
-    def set_binary(fd):
-        # When run without console, pipes may expose invalid
-        # fileno(), usually set to -1.
-        if hasattr(fd, 'fileno') and fd.fileno() >= 0:
-            msvcrt.setmode(fd.fileno(), os.O_BINARY)
-
-    def pconvert(path):
-        return '/'.join(splitpath(path))
-
-    def localpath(path):
-        return path.replace('/', '\\')
-
-    def normpath(path):
-        return pconvert(os.path.normpath(path))
-
-    makelock = _makelock_file
-    readlock = _readlock_file
-
-    def samestat(s1, s2):
-        return False
-
-    # A sequence of backslashes is special iff it precedes a double quote:
-    # - if there's an even number of backslashes, the double quote is not
-    #   quoted (i.e. it ends the quoted region)
-    # - if there's an odd number of backslashes, the double quote is quoted
-    # - in both cases, every pair of backslashes is unquoted into a single
-    #   backslash
-    # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
-    # So, to quote a string, we must surround it in double quotes, double
-    # the number of backslashes that preceed double quotes and add another
-    # backslash before every double quote (being careful with the double
-    # quote we've appended to the end)
-    _quotere = None
-    def shellquote(s):
-        global _quotere
-        if _quotere is None:
-            _quotere = re.compile(r'(\\*)("|\\$)')
-        return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
-
-    def quotecommand(cmd):
-        """Build a command string suitable for os.popen* calls."""
-        # The extra quotes are needed because popen* runs the command
-        # through the current COMSPEC. cmd.exe suppress enclosing quotes.
-        return '"' + cmd + '"'
-
-    def popen(command, mode='r'):
-        # Work around "popen spawned process may not write to stdout
-        # under windows"
-        # http://bugs.python.org/issue1366
-        command += " 2> %s" % nulldev
-        return os.popen(quotecommand(command), mode)
-
-    def explain_exit(code):
-        return _("exited with status %d") % code, code
-
-    # if you change this stub into a real check, please try to implement the
-    # username and groupname functions above, too.
-    def isowner(fp, st=None):
-        return True
-
-    def find_exe(command):
-        '''Find executable for command searching like cmd.exe does.
-        If command is a basename then PATH is searched for command.
-        PATH isn't searched if command is an absolute or relative path.
-        An extension from PATHEXT is found and added if not present.
-        If command isn't found None is returned.'''
-        pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
-        pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
-        if os.path.splitext(command)[1].lower() in pathexts:
-            pathexts = ['']
-
-        def findexisting(pathcommand):
-            'Will append extension (if needed) and return existing file'
-            for ext in pathexts:
-                executable = pathcommand + ext
-                if os.path.exists(executable):
-                    return executable
-            return None
-
-        if os.sep in command:
-            return findexisting(command)
-
-        for path in os.environ.get('PATH', '').split(os.pathsep):
-            executable = findexisting(os.path.join(path, command))
-            if executable is not None:
-                return executable
-        return None
-
-    def set_signal_handler():
-        try:
-            set_signal_handler_win32()
-        except NameError:
-            pass
-
-    try:
-        # override functions with win32 versions if possible
-        from util_win32 import *
-        if not _is_win_9x():
-            posixfile = posixfile_nt
-    except ImportError:
-        pass
-
-else:
-    nulldev = '/dev/null'
-
-    def rcfiles(path):
-        rcs = [os.path.join(path, 'hgrc')]
-        rcdir = os.path.join(path, 'hgrc.d')
-        try:
-            rcs.extend([os.path.join(rcdir, f)
-                        for f, kind in osutil.listdir(rcdir)
-                        if f.endswith(".rc")])
-        except OSError:
-            pass
-        return rcs
-
-    def system_rcpath():
-        path = []
-        # old mod_python does not set sys.argv
-        if len(getattr(sys, 'argv', [])) > 0:
-            path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
-                                  '/../etc/mercurial'))
-        path.extend(rcfiles('/etc/mercurial'))
-        return path
-
-    def user_rcpath():
-        return [os.path.expanduser('~/.hgrc')]
-
-    def parse_patch_output(output_line):
-        """parses the output produced by patch and returns the file name"""
-        pf = output_line[14:]
-        if os.sys.platform == 'OpenVMS':
-            if pf[0] == '`':
-                pf = pf[1:-1] # Remove the quotes
-        else:
-           if pf.startswith("'") and pf.endswith("'") and " " in pf:
-                pf = pf[1:-1] # Remove the quotes
-        return pf
-
-    def sshargs(sshcmd, host, user, port):
-        '''Build argument list for ssh'''
-        args = user and ("%s@%s" % (user, host)) or host
-        return port and ("%s -p %s" % (args, port)) or args
-
-    def is_exec(f):
-        """check whether a file is executable"""
-        return (os.lstat(f).st_mode & 0100 != 0)
-
-    def set_flags(f, l, x):
-        s = os.lstat(f).st_mode
-        if l:
-            if not stat.S_ISLNK(s):
-                # switch file to link
-                data = file(f).read()
-                os.unlink(f)
-                try:
-                    os.symlink(data, f)
-                except:
-                    # failed to make a link, rewrite file
-                    file(f, "w").write(data)
-            # no chmod needed at this point
-            return
-        if stat.S_ISLNK(s):
-            # switch link to file
-            data = os.readlink(f)
-            os.unlink(f)
-            file(f, "w").write(data)
-            s = 0666 & ~_umask # avoid restatting for chmod
-
-        sx = s & 0100
-        if x and not sx:
-            # Turn on +x for every +r bit when making a file executable
-            # and obey umask.
-            os.chmod(f, s | (s & 0444) >> 2 & ~_umask)
-        elif not x and sx:
-            # Turn off all +x bits
-            os.chmod(f, s & 0666)
-
-    def set_binary(fd):
-        pass
-
-    def pconvert(path):
-        return path
-
-    def localpath(path):
-        return path
-
-    normpath = os.path.normpath
-    samestat = os.path.samestat
-
-    def makelock(info, pathname):
-        try:
-            os.symlink(info, pathname)
-        except OSError, why:
-            if why.errno == errno.EEXIST:
-                raise
-            else:
-                _makelock_file(info, pathname)
-
-    def readlock(pathname):
-        try:
-            return os.readlink(pathname)
-        except OSError, why:
-            if why.errno in (errno.EINVAL, errno.ENOSYS):
-                return _readlock_file(pathname)
-            else:
-                raise
-
-    def shellquote(s):
-        if os.sys.platform == 'OpenVMS':
-            return '"%s"' % s
-        else:
-            return "'%s'" % s.replace("'", "'\\''")
-
-    def quotecommand(cmd):
-        return cmd
-
-    def popen(command, mode='r'):
-        return os.popen(command, mode)
-
-    def testpid(pid):
-        '''return False if pid dead, True if running or not sure'''
-        if os.sys.platform == 'OpenVMS':
-            return True
-        try:
-            os.kill(pid, 0)
-            return True
-        except OSError, inst:
-            return inst.errno != errno.ESRCH
-
-    def explain_exit(code):
-        """return a 2-tuple (desc, code) describing a process's status"""
-        if os.WIFEXITED(code):
-            val = os.WEXITSTATUS(code)
-            return _("exited with status %d") % val, val
-        elif os.WIFSIGNALED(code):
-            val = os.WTERMSIG(code)
-            return _("killed by signal %d") % val, val
-        elif os.WIFSTOPPED(code):
-            val = os.WSTOPSIG(code)
-            return _("stopped by signal %d") % val, val
-        raise ValueError(_("invalid exit code"))
-
-    def isowner(fp, st=None):
-        """Return True if the file object f belongs to the current user.
-
-        The return value of a util.fstat(f) may be passed as the st argument.
-        """
-        if st is None:
-            st = fstat(fp)
-        return st.st_uid == os.getuid()
-
-    def find_exe(command):
-        '''Find executable for command searching like which does.
-        If command is a basename then PATH is searched for command.
-        PATH isn't searched if command is an absolute or relative path.
-        If command isn't found None is returned.'''
-        if sys.platform == 'OpenVMS':
-            return command
-
-        def findexisting(executable):
-            'Will return executable if existing file'
-            if os.path.exists(executable):
-                return executable
-            return None
-
-        if os.sep in command:
-            return findexisting(command)
-
-        for path in os.environ.get('PATH', '').split(os.pathsep):
-            executable = findexisting(os.path.join(path, command))
-            if executable is not None:
-                return executable
-        return None
-
-    def set_signal_handler():
-        pass
-
 def mktempcopy(name, emptyok=False, createmode=None):
     """Create a temporary file with the same contents from name
 
@@ -1510,7 +1041,7 @@
             raise
         st_mode = createmode
         if st_mode is None:
-            st_mode = ~_umask
+            st_mode = ~umask
         st_mode &= 0666
     os.chmod(temp, st_mode)
     if emptyok:
--- a/mercurial/util_win32.py	Sat Mar 14 10:46:48 2009 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,375 +0,0 @@
-# util_win32.py - utility functions that use win32 API
-#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
-# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
-#
-# 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)
-
-getuser_fallback = 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)
--- /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)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/windows.py	Thu Mar 26 13:54:44 2009 -0500
@@ -0,0 +1,266 @@
+"""
+windows.py - Windows utility function implementations for Mercurial
+
+ 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 version 2, incorporated herein by
+reference.
+"""
+
+import msvcrt, sys, os
+nulldev = 'NUL:'
+
+umask = 002
+
+class winstdout:
+    '''stdout on windows misbehaves if sent through a pipe'''
+
+    def __init__(self, fp):
+        self.fp = fp
+
+    def __getattr__(self, key):
+        return getattr(self.fp, key)
+
+    def close(self):
+        try:
+            self.fp.close()
+        except: pass
+
+    def write(self, s):
+        try:
+            # This is workaround for "Not enough space" error on
+            # writing large size of data to console.
+            limit = 16000
+            l = len(s)
+            start = 0
+            while start < l:
+                end = start + limit
+                self.fp.write(s[start:end])
+                start = end
+        except IOError, inst:
+            if inst.errno != 0: raise
+            self.close()
+            raise IOError(errno.EPIPE, 'Broken pipe')
+
+    def flush(self):
+        try:
+            return self.fp.flush()
+        except IOError, inst:
+            if inst.errno != errno.EINVAL: raise
+            self.close()
+            raise IOError(errno.EPIPE, 'Broken pipe')
+
+sys.stdout = winstdout(sys.stdout)
+
+def _is_win_9x():
+    '''return true if run on windows 95, 98 or me.'''
+    try:
+        return sys.getwindowsversion()[3] == 1
+    except AttributeError:
+        return 'command' in os.environ.get('comspec', '')
+
+def openhardlinks():
+    return not _is_win_9x and "win32api" in locals()
+
+def system_rcpath():
+    try:
+        return system_rcpath_win32()
+    except:
+        return [r'c:\mercurial\mercurial.ini']
+
+def user_rcpath():
+    '''return os-specific hgrc search path to the user dir'''
+    try:
+        path = user_rcpath_win32()
+    except:
+        home = os.path.expanduser('~')
+        path = [os.path.join(home, 'mercurial.ini'),
+                os.path.join(home, '.hgrc')]
+    userprofile = os.environ.get('USERPROFILE')
+    if userprofile:
+        path.append(os.path.join(userprofile, 'mercurial.ini'))
+        path.append(os.path.join(userprofile, '.hgrc'))
+    return path
+
+def parse_patch_output(output_line):
+    """parses the output produced by patch and returns the file name"""
+    pf = output_line[14:]
+    if pf[0] == '`':
+        pf = pf[1:-1] # Remove the quotes
+    return pf
+
+def sshargs(sshcmd, host, user, port):
+    '''Build argument list for ssh or Plink'''
+    pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
+    args = user and ("%s@%s" % (user, host)) or host
+    return port and ("%s %s %s" % (args, pflag, port)) or args
+
+def testpid(pid):
+    '''return False if pid dead, True if running or not known'''
+    return True
+
+def set_flags(f, l, x):
+    pass
+
+def set_binary(fd):
+    # When run without console, pipes may expose invalid
+    # fileno(), usually set to -1.
+    if hasattr(fd, 'fileno') and fd.fileno() >= 0:
+        msvcrt.setmode(fd.fileno(), os.O_BINARY)
+
+def pconvert(path):
+    return '/'.join(path.split(os.sep))
+
+def localpath(path):
+    return path.replace('/', '\\')
+
+def normpath(path):
+    return pconvert(os.path.normpath(path))
+
+def samestat(s1, s2):
+    return False
+
+# A sequence of backslashes is special iff it precedes a double quote:
+# - if there's an even number of backslashes, the double quote is not
+#   quoted (i.e. it ends the quoted region)
+# - if there's an odd number of backslashes, the double quote is quoted
+# - in both cases, every pair of backslashes is unquoted into a single
+#   backslash
+# (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
+# So, to quote a string, we must surround it in double quotes, double
+# the number of backslashes that preceed double quotes and add another
+# backslash before every double quote (being careful with the double
+# quote we've appended to the end)
+_quotere = None
+def shellquote(s):
+    global _quotere
+    if _quotere is None:
+        _quotere = re.compile(r'(\\*)("|\\$)')
+    return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
+
+def quotecommand(cmd):
+    """Build a command string suitable for os.popen* calls."""
+    # The extra quotes are needed because popen* runs the command
+    # through the current COMSPEC. cmd.exe suppress enclosing quotes.
+    return '"' + cmd + '"'
+
+def popen(command, mode='r'):
+    # Work around "popen spawned process may not write to stdout
+    # under windows"
+    # http://bugs.python.org/issue1366
+    command += " 2> %s" % nulldev
+    return os.popen(quotecommand(command), mode)
+
+def explain_exit(code):
+    return _("exited with status %d") % code, code
+
+# if you change this stub into a real check, please try to implement the
+# username and groupname functions above, too.
+def isowner(fp, st=None):
+    return True
+
+def find_exe(command):
+    '''Find executable for command searching like cmd.exe does.
+    If command is a basename then PATH is searched for command.
+    PATH isn't searched if command is an absolute or relative path.
+    An extension from PATHEXT is found and added if not present.
+    If command isn't found None is returned.'''
+    pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
+    pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
+    if os.path.splitext(command)[1].lower() in pathexts:
+        pathexts = ['']
+
+    def findexisting(pathcommand):
+        'Will append extension (if needed) and return existing file'
+        for ext in pathexts:
+            executable = pathcommand + ext
+            if os.path.exists(executable):
+                return executable
+        return None
+
+    if os.sep in command:
+        return findexisting(command)
+
+    for path in os.environ.get('PATH', '').split(os.pathsep):
+        executable = findexisting(os.path.join(path, command))
+        if executable is not None:
+            return executable
+    return None
+
+def set_signal_handler():
+    try:
+        set_signal_handler_win32()
+    except NameError:
+        pass
+
+def statfiles(files):
+    '''Stat each file in files and yield stat or None if file does not exist.
+    Cluster and cache stat per directory to minimize number of OS stat calls.'''
+    ncase = os.path.normcase
+    sep   = os.sep
+    dircache = {} # dirname -> filename -> status | None if file does not exist
+    for nf in files:
+        nf  = ncase(nf)
+        pos = nf.rfind(sep)
+        if pos == -1:
+            dir, base = '.', nf
+        else:
+            dir, base = nf[:pos+1], nf[pos+1:]
+        cache = dircache.get(dir, None)
+        if cache is None:
+            try:
+                dmap = dict([(ncase(n), s)
+                    for n, k, s in osutil.listdir(dir, True)])
+            except OSError, err:
+                # handle directory not found in Python version prior to 2.5
+                # Python <= 2.4 returns native Windows code 3 in errno
+                # Python >= 2.5 returns ENOENT and adds winerror field
+                # EINVAL is raised if dir is not a directory.
+                if err.errno not in (3, errno.ENOENT, errno.EINVAL,
+                                     errno.ENOTDIR):
+                    raise
+                dmap = {}
+            cache = dircache.setdefault(dir, dmap)
+        yield cache.get(base, None)
+
+def getuser():
+    '''return name of current user'''
+    raise Abort(_('user name not available - set USERNAME '
+                  'environment variable'))
+
+def expand_glob(pats):
+    '''On Windows, expand the implicit globs in a list of patterns'''
+    ret = []
+    for p in pats:
+        kind, name = patkind(p, None)
+        if kind is None:
+            globbed = glob.glob(name)
+            if globbed:
+                ret.extend(globbed)
+                continue
+            # if we couldn't expand the glob, just keep it around
+        ret.append(p)
+    return ret
+
+def username(uid=None):
+    """Return the name of the user with the given uid.
+
+    If uid is None, return the name of the current user."""
+    return None
+
+def groupname(gid=None):
+    """Return the name of the group with the given gid.
+
+    If gid is None, return the name of the current group."""
+    return None
+
+posixfile = file
+try:
+    # override functions with win32 versions if possible
+    from util_win32 import *
+    if not _is_win_9x():
+        posixfile = posixfile_nt
+except ImportError:
+    pass
+