mercurial/windows.py
changeset 43076 2372284d9457
parent 41289 593f6359681d
child 43077 687b865b95ad
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
    24     win32,
    24     win32,
    25 )
    25 )
    26 
    26 
    27 try:
    27 try:
    28     import _winreg as winreg
    28     import _winreg as winreg
       
    29 
    29     winreg.CloseKey
    30     winreg.CloseKey
    30 except ImportError:
    31 except ImportError:
    31     import winreg
    32     import winreg
    32 
    33 
    33 osutil = policy.importmod(r'osutil')
    34 osutil = policy.importmod(r'osutil')
    47 testpid = win32.testpid
    48 testpid = win32.testpid
    48 unlink = win32.unlink
    49 unlink = win32.unlink
    49 
    50 
    50 umask = 0o022
    51 umask = 0o022
    51 
    52 
       
    53 
    52 class mixedfilemodewrapper(object):
    54 class mixedfilemodewrapper(object):
    53     """Wraps a file handle when it is opened in read/write mode.
    55     """Wraps a file handle when it is opened in read/write mode.
    54 
    56 
    55     fopen() and fdopen() on Windows have a specific-to-Windows requirement
    57     fopen() and fdopen() on Windows have a specific-to-Windows requirement
    56     that files opened with mode r+, w+, or a+ make a call to a file positioning
    58     that files opened with mode r+, w+, or a+ make a call to a file positioning
    59 
    61 
    60     This class wraps posixfile instances when the file is opened in read/write
    62     This class wraps posixfile instances when the file is opened in read/write
    61     mode and automatically adds checks or inserts appropriate file positioning
    63     mode and automatically adds checks or inserts appropriate file positioning
    62     calls when necessary.
    64     calls when necessary.
    63     """
    65     """
       
    66 
    64     OPNONE = 0
    67     OPNONE = 0
    65     OPREAD = 1
    68     OPREAD = 1
    66     OPWRITE = 2
    69     OPWRITE = 2
    67 
    70 
    68     def __init__(self, fp):
    71     def __init__(self, fp):
   121         if self._lastop == self.OPWRITE:
   124         if self._lastop == self.OPWRITE:
   122             self._noopseek()
   125             self._noopseek()
   123 
   126 
   124         object.__setattr__(self, r'_lastop', self.OPREAD)
   127         object.__setattr__(self, r'_lastop', self.OPREAD)
   125         return self._fp.readlines(*args, **kwargs)
   128         return self._fp.readlines(*args, **kwargs)
       
   129 
   126 
   130 
   127 class fdproxy(object):
   131 class fdproxy(object):
   128     """Wraps osutil.posixfile() to override the name attribute to reflect the
   132     """Wraps osutil.posixfile() to override the name attribute to reflect the
   129     underlying file name.
   133     underlying file name.
   130     """
   134     """
       
   135 
   131     def __init__(self, name, fp):
   136     def __init__(self, name, fp):
   132         self.name = name
   137         self.name = name
   133         self._fp = fp
   138         self._fp = fp
   134 
   139 
   135     def __enter__(self):
   140     def __enter__(self):
   145         return iter(self._fp)
   150         return iter(self._fp)
   146 
   151 
   147     def __getattr__(self, name):
   152     def __getattr__(self, name):
   148         return getattr(self._fp, name)
   153         return getattr(self._fp, name)
   149 
   154 
       
   155 
   150 def posixfile(name, mode='r', buffering=-1):
   156 def posixfile(name, mode='r', buffering=-1):
   151     '''Open a file with even more POSIX-like semantics'''
   157     '''Open a file with even more POSIX-like semantics'''
   152     try:
   158     try:
   153         fp = osutil.posixfile(name, mode, buffering) # may raise WindowsError
   159         fp = osutil.posixfile(name, mode, buffering)  # may raise WindowsError
   154 
   160 
   155         # PyFile_FromFd() ignores the name, and seems to report fp.name as the
   161         # PyFile_FromFd() ignores the name, and seems to report fp.name as the
   156         # underlying file descriptor.
   162         # underlying file descriptor.
   157         if pycompat.ispy3:
   163         if pycompat.ispy3:
   158             fp = fdproxy(name, fp)
   164             fp = fdproxy(name, fp)
   166             return mixedfilemodewrapper(fp)
   172             return mixedfilemodewrapper(fp)
   167 
   173 
   168         return fp
   174         return fp
   169     except WindowsError as err:
   175     except WindowsError as err:
   170         # convert to a friendlier exception
   176         # convert to a friendlier exception
   171         raise IOError(err.errno, r'%s: %s' % (
   177         raise IOError(
   172             encoding.strfromlocal(name), err.strerror))
   178             err.errno, r'%s: %s' % (encoding.strfromlocal(name), err.strerror)
       
   179         )
       
   180 
   173 
   181 
   174 # may be wrapped by win32mbcs extension
   182 # may be wrapped by win32mbcs extension
   175 listdir = osutil.listdir
   183 listdir = osutil.listdir
       
   184 
   176 
   185 
   177 class winstdout(object):
   186 class winstdout(object):
   178     '''stdout on windows misbehaves if sent through a pipe'''
   187     '''stdout on windows misbehaves if sent through a pipe'''
   179 
   188 
   180     def __init__(self, fp):
   189     def __init__(self, fp):
   213         except IOError as inst:
   222         except IOError as inst:
   214             if not win32.lasterrorwaspipeerror(inst):
   223             if not win32.lasterrorwaspipeerror(inst):
   215                 raise
   224                 raise
   216             raise IOError(errno.EPIPE, r'Broken pipe')
   225             raise IOError(errno.EPIPE, r'Broken pipe')
   217 
   226 
       
   227 
   218 def _is_win_9x():
   228 def _is_win_9x():
   219     '''return true if run on windows 95, 98 or me.'''
   229     '''return true if run on windows 95, 98 or me.'''
   220     try:
   230     try:
   221         return sys.getwindowsversion()[3] == 1
   231         return sys.getwindowsversion()[3] == 1
   222     except AttributeError:
   232     except AttributeError:
   223         return 'command' in encoding.environ.get('comspec', '')
   233         return 'command' in encoding.environ.get('comspec', '')
   224 
   234 
       
   235 
   225 def openhardlinks():
   236 def openhardlinks():
   226     return not _is_win_9x()
   237     return not _is_win_9x()
       
   238 
   227 
   239 
   228 def parsepatchoutput(output_line):
   240 def parsepatchoutput(output_line):
   229     """parses the output produced by patch and returns the filename"""
   241     """parses the output produced by patch and returns the filename"""
   230     pf = output_line[14:]
   242     pf = output_line[14:]
   231     if pf[0] == '`':
   243     if pf[0] == '`':
   232         pf = pf[1:-1] # Remove the quotes
   244         pf = pf[1:-1]  # Remove the quotes
   233     return pf
   245     return pf
       
   246 
   234 
   247 
   235 def sshargs(sshcmd, host, user, port):
   248 def sshargs(sshcmd, host, user, port):
   236     '''Build argument list for ssh or Plink'''
   249     '''Build argument list for ssh or Plink'''
   237     pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
   250     pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
   238     args = user and ("%s@%s" % (user, host)) or host
   251     args = user and ("%s@%s" % (user, host)) or host
   239     if args.startswith('-') or args.startswith('/'):
   252     if args.startswith('-') or args.startswith('/'):
   240         raise error.Abort(
   253         raise error.Abort(
   241             _('illegal ssh hostname or username starting with - or /: %s') %
   254             _('illegal ssh hostname or username starting with - or /: %s')
   242             args)
   255             % args
       
   256         )
   243     args = shellquote(args)
   257     args = shellquote(args)
   244     if port:
   258     if port:
   245         args = '%s %s %s' % (pflag, shellquote(port), args)
   259         args = '%s %s %s' % (pflag, shellquote(port), args)
   246     return args
   260     return args
   247 
   261 
       
   262 
   248 def setflags(f, l, x):
   263 def setflags(f, l, x):
   249     pass
   264     pass
   250 
   265 
       
   266 
   251 def copymode(src, dst, mode=None, enforcewritable=False):
   267 def copymode(src, dst, mode=None, enforcewritable=False):
   252     pass
   268     pass
   253 
   269 
       
   270 
   254 def checkexec(path):
   271 def checkexec(path):
   255     return False
   272     return False
   256 
   273 
       
   274 
   257 def checklink(path):
   275 def checklink(path):
   258     return False
   276     return False
       
   277 
   259 
   278 
   260 def setbinary(fd):
   279 def setbinary(fd):
   261     # When run without console, pipes may expose invalid
   280     # When run without console, pipes may expose invalid
   262     # fileno(), usually set to -1.
   281     # fileno(), usually set to -1.
   263     fno = getattr(fd, 'fileno', None)
   282     fno = getattr(fd, 'fileno', None)
   264     if fno is not None and fno() >= 0:
   283     if fno is not None and fno() >= 0:
   265         msvcrt.setmode(fno(), os.O_BINARY)
   284         msvcrt.setmode(fno(), os.O_BINARY)
   266 
   285 
       
   286 
   267 def pconvert(path):
   287 def pconvert(path):
   268     return path.replace(pycompat.ossep, '/')
   288     return path.replace(pycompat.ossep, '/')
   269 
   289 
       
   290 
   270 def localpath(path):
   291 def localpath(path):
   271     return path.replace('/', '\\')
   292     return path.replace('/', '\\')
   272 
   293 
       
   294 
   273 def normpath(path):
   295 def normpath(path):
   274     return pconvert(os.path.normpath(path))
   296     return pconvert(os.path.normpath(path))
   275 
   297 
       
   298 
   276 def normcase(path):
   299 def normcase(path):
   277     return encoding.upper(path) # NTFS compares via upper()
   300     return encoding.upper(path)  # NTFS compares via upper()
       
   301 
   278 
   302 
   279 # see posix.py for definitions
   303 # see posix.py for definitions
   280 normcasespec = encoding.normcasespecs.upper
   304 normcasespec = encoding.normcasespecs.upper
   281 normcasefallback = encoding.upperfallback
   305 normcasefallback = encoding.upperfallback
   282 
   306 
       
   307 
   283 def samestat(s1, s2):
   308 def samestat(s1, s2):
   284     return False
   309     return False
       
   310 
   285 
   311 
   286 def shelltocmdexe(path, env):
   312 def shelltocmdexe(path, env):
   287     r"""Convert shell variables in the form $var and ${var} inside ``path``
   313     r"""Convert shell variables in the form $var and ${var} inside ``path``
   288     to %var% form.  Existing Windows style variables are left unchanged.
   314     to %var% form.  Existing Windows style variables are left unchanged.
   289 
   315 
   316 
   342 
   317     res = b''
   343     res = b''
   318     index = 0
   344     index = 0
   319     pathlen = len(path)
   345     pathlen = len(path)
   320     while index < pathlen:
   346     while index < pathlen:
   321         c = path[index:index + 1]
   347         c = path[index : index + 1]
   322         if c == b'\'':   # no expansion within single quotes
   348         if c == b'\'':  # no expansion within single quotes
   323             path = path[index + 1:]
   349             path = path[index + 1 :]
   324             pathlen = len(path)
   350             pathlen = len(path)
   325             try:
   351             try:
   326                 index = path.index(b'\'')
   352                 index = path.index(b'\'')
   327                 res += b'"' + path[:index] + b'"'
   353                 res += b'"' + path[:index] + b'"'
   328             except ValueError:
   354             except ValueError:
   329                 res += c + path
   355                 res += c + path
   330                 index = pathlen - 1
   356                 index = pathlen - 1
   331         elif c == b'%':  # variable
   357         elif c == b'%':  # variable
   332             path = path[index + 1:]
   358             path = path[index + 1 :]
   333             pathlen = len(path)
   359             pathlen = len(path)
   334             try:
   360             try:
   335                 index = path.index(b'%')
   361                 index = path.index(b'%')
   336             except ValueError:
   362             except ValueError:
   337                 res += b'%' + path
   363                 res += b'%' + path
   338                 index = pathlen - 1
   364                 index = pathlen - 1
   339             else:
   365             else:
   340                 var = path[:index]
   366                 var = path[:index]
   341                 res += b'%' + var + b'%'
   367                 res += b'%' + var + b'%'
   342         elif c == b'$':  # variable
   368         elif c == b'$':  # variable
   343             if path[index + 1:index + 2] == b'{':
   369             if path[index + 1 : index + 2] == b'{':
   344                 path = path[index + 2:]
   370                 path = path[index + 2 :]
   345                 pathlen = len(path)
   371                 pathlen = len(path)
   346                 try:
   372                 try:
   347                     index = path.index(b'}')
   373                     index = path.index(b'}')
   348                     var = path[:index]
   374                     var = path[:index]
   349 
   375 
   356                     res += b'${' + path
   382                     res += b'${' + path
   357                     index = pathlen - 1
   383                     index = pathlen - 1
   358             else:
   384             else:
   359                 var = b''
   385                 var = b''
   360                 index += 1
   386                 index += 1
   361                 c = path[index:index + 1]
   387                 c = path[index : index + 1]
   362                 while c != b'' and c in varchars:
   388                 while c != b'' and c in varchars:
   363                     var += c
   389                     var += c
   364                     index += 1
   390                     index += 1
   365                     c = path[index:index + 1]
   391                     c = path[index : index + 1]
   366                 # Some variables (like HG_OLDNODE) may be defined, but have an
   392                 # Some variables (like HG_OLDNODE) may be defined, but have an
   367                 # empty value.  Those need to be skipped because when spawning
   393                 # empty value.  Those need to be skipped because when spawning
   368                 # cmd.exe to run the hook, it doesn't replace %VAR% for an empty
   394                 # cmd.exe to run the hook, it doesn't replace %VAR% for an empty
   369                 # VAR, and that really confuses things like revset expressions.
   395                 # VAR, and that really confuses things like revset expressions.
   370                 # OTOH, if it's left in Unix format and the hook runs sh.exe, it
   396                 # OTOH, if it's left in Unix format and the hook runs sh.exe, it
   374                 else:
   400                 else:
   375                     res += b'$' + var
   401                     res += b'$' + var
   376 
   402 
   377                 if c != b'':
   403                 if c != b'':
   378                     index -= 1
   404                     index -= 1
   379         elif (c == b'~' and index + 1 < pathlen
   405         elif (
   380               and path[index + 1:index + 2] in (b'\\', b'/')):
   406             c == b'~'
       
   407             and index + 1 < pathlen
       
   408             and path[index + 1 : index + 2] in (b'\\', b'/')
       
   409         ):
   381             res += "%USERPROFILE%"
   410             res += "%USERPROFILE%"
   382         elif (c == b'\\' and index + 1 < pathlen
   411         elif (
   383               and path[index + 1:index + 2] in (b'$', b'~')):
   412             c == b'\\'
       
   413             and index + 1 < pathlen
       
   414             and path[index + 1 : index + 2] in (b'$', b'~')
       
   415         ):
   384             # Skip '\', but only if it is escaping $ or ~
   416             # Skip '\', but only if it is escaping $ or ~
   385             res += path[index + 1:index + 2]
   417             res += path[index + 1 : index + 2]
   386             index += 1
   418             index += 1
   387         else:
   419         else:
   388             res += c
   420             res += c
   389 
   421 
   390         index += 1
   422         index += 1
   391     return res
   423     return res
       
   424 
   392 
   425 
   393 # A sequence of backslashes is special iff it precedes a double quote:
   426 # A sequence of backslashes is special iff it precedes a double quote:
   394 # - if there's an even number of backslashes, the double quote is not
   427 # - if there's an even number of backslashes, the double quote is not
   395 #   quoted (i.e. it ends the quoted region)
   428 #   quoted (i.e. it ends the quoted region)
   396 # - if there's an odd number of backslashes, the double quote is quoted
   429 # - if there's an odd number of backslashes, the double quote is quoted
   401 # the number of backslashes that precede double quotes and add another
   434 # the number of backslashes that precede double quotes and add another
   402 # backslash before every double quote (being careful with the double
   435 # backslash before every double quote (being careful with the double
   403 # quote we've appended to the end)
   436 # quote we've appended to the end)
   404 _quotere = None
   437 _quotere = None
   405 _needsshellquote = None
   438 _needsshellquote = None
       
   439 
       
   440 
   406 def shellquote(s):
   441 def shellquote(s):
   407     r"""
   442     r"""
   408     >>> shellquote(br'C:\Users\xyz')
   443     >>> shellquote(br'C:\Users\xyz')
   409     '"C:\\Users\\xyz"'
   444     '"C:\\Users\\xyz"'
   410     >>> shellquote(br'C:\Users\xyz/mixed')
   445     >>> shellquote(br'C:\Users\xyz/mixed')
   430     if s and not _needsshellquote(s) and not _quotere.search(s):
   465     if s and not _needsshellquote(s) and not _quotere.search(s):
   431         # "s" shouldn't have to be quoted
   466         # "s" shouldn't have to be quoted
   432         return s
   467         return s
   433     return b'"%s"' % _quotere.sub(br'\1\1\\\2', s)
   468     return b'"%s"' % _quotere.sub(br'\1\1\\\2', s)
   434 
   469 
       
   470 
   435 def _unquote(s):
   471 def _unquote(s):
   436     if s.startswith(b'"') and s.endswith(b'"'):
   472     if s.startswith(b'"') and s.endswith(b'"'):
   437         return s[1:-1]
   473         return s[1:-1]
   438     return s
   474     return s
   439 
   475 
       
   476 
   440 def shellsplit(s):
   477 def shellsplit(s):
   441     """Parse a command string in cmd.exe way (best-effort)"""
   478     """Parse a command string in cmd.exe way (best-effort)"""
   442     return pycompat.maplist(_unquote, pycompat.shlexsplit(s, posix=False))
   479     return pycompat.maplist(_unquote, pycompat.shlexsplit(s, posix=False))
       
   480 
   443 
   481 
   444 def quotecommand(cmd):
   482 def quotecommand(cmd):
   445     """Build a command string suitable for os.popen* calls."""
   483     """Build a command string suitable for os.popen* calls."""
   446     if sys.version_info < (2, 7, 1):
   484     if sys.version_info < (2, 7, 1):
   447         # Python versions since 2.7.1 do this extra quoting themselves
   485         # Python versions since 2.7.1 do this extra quoting themselves
   448         return '"' + cmd + '"'
   486         return '"' + cmd + '"'
   449     return cmd
   487     return cmd
   450 
   488 
       
   489 
   451 # if you change this stub into a real check, please try to implement the
   490 # if you change this stub into a real check, please try to implement the
   452 # username and groupname functions above, too.
   491 # username and groupname functions above, too.
   453 def isowner(st):
   492 def isowner(st):
   454     return True
   493     return True
       
   494 
   455 
   495 
   456 def findexe(command):
   496 def findexe(command):
   457     '''Find executable for command searching like cmd.exe does.
   497     '''Find executable for command searching like cmd.exe does.
   458     If command is a basename then PATH is searched for command.
   498     If command is a basename then PATH is searched for command.
   459     PATH isn't searched if command is an absolute or relative path.
   499     PATH isn't searched if command is an absolute or relative path.
   479         executable = findexisting(os.path.join(path, command))
   519         executable = findexisting(os.path.join(path, command))
   480         if executable is not None:
   520         if executable is not None:
   481             return executable
   521             return executable
   482     return findexisting(os.path.expanduser(os.path.expandvars(command)))
   522     return findexisting(os.path.expanduser(os.path.expandvars(command)))
   483 
   523 
       
   524 
   484 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK}
   525 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK}
       
   526 
   485 
   527 
   486 def statfiles(files):
   528 def statfiles(files):
   487     '''Stat each file in files. Yield each stat, or None if a file
   529     '''Stat each file in files. Yield each stat, or None if a file
   488     does not exist or has a type we don't care about.
   530     does not exist or has a type we don't care about.
   489 
   531 
   490     Cluster and cache stat per directory to minimize number of OS stat calls.'''
   532     Cluster and cache stat per directory to minimize number of OS stat calls.'''
   491     dircache = {} # dirname -> filename -> status | None if file does not exist
   533     dircache = {}  # dirname -> filename -> status | None if file does not exist
   492     getkind = stat.S_IFMT
   534     getkind = stat.S_IFMT
   493     for nf in files:
   535     for nf in files:
   494         nf  = normcase(nf)
   536         nf = normcase(nf)
   495         dir, base = os.path.split(nf)
   537         dir, base = os.path.split(nf)
   496         if not dir:
   538         if not dir:
   497             dir = '.'
   539             dir = '.'
   498         cache = dircache.get(dir, None)
   540         cache = dircache.get(dir, None)
   499         if cache is None:
   541         if cache is None:
   500             try:
   542             try:
   501                 dmap = dict([(normcase(n), s)
   543                 dmap = dict(
   502                              for n, k, s in listdir(dir, True)
   544                     [
   503                              if getkind(s.st_mode) in _wantedkinds])
   545                         (normcase(n), s)
       
   546                         for n, k, s in listdir(dir, True)
       
   547                         if getkind(s.st_mode) in _wantedkinds
       
   548                     ]
       
   549                 )
   504             except OSError as err:
   550             except OSError as err:
   505                 # Python >= 2.5 returns ENOENT and adds winerror field
   551                 # Python >= 2.5 returns ENOENT and adds winerror field
   506                 # EINVAL is raised if dir is not a directory.
   552                 # EINVAL is raised if dir is not a directory.
   507                 if err.errno not in (errno.ENOENT, errno.EINVAL,
   553                 if err.errno not in (errno.ENOENT, errno.EINVAL, errno.ENOTDIR):
   508                                      errno.ENOTDIR):
       
   509                     raise
   554                     raise
   510                 dmap = {}
   555                 dmap = {}
   511             cache = dircache.setdefault(dir, dmap)
   556             cache = dircache.setdefault(dir, dmap)
   512         yield cache.get(base, None)
   557         yield cache.get(base, None)
   513 
   558 
       
   559 
   514 def username(uid=None):
   560 def username(uid=None):
   515     """Return the name of the user with the given uid.
   561     """Return the name of the user with the given uid.
   516 
   562 
   517     If uid is None, return the name of the current user."""
   563     If uid is None, return the name of the current user."""
   518     return None
   564     return None
   519 
   565 
       
   566 
   520 def groupname(gid=None):
   567 def groupname(gid=None):
   521     """Return the name of the group with the given gid.
   568     """Return the name of the group with the given gid.
   522 
   569 
   523     If gid is None, return the name of the current group."""
   570     If gid is None, return the name of the current group."""
   524     return None
   571     return None
   525 
   572 
       
   573 
   526 def readlink(pathname):
   574 def readlink(pathname):
   527     return pycompat.fsencode(os.readlink(pycompat.fsdecode(pathname)))
   575     return pycompat.fsencode(os.readlink(pycompat.fsdecode(pathname)))
       
   576 
   528 
   577 
   529 def removedirs(name):
   578 def removedirs(name):
   530     """special version of os.removedirs that does not remove symlinked
   579     """special version of os.removedirs that does not remove symlinked
   531     directories or junction points if they actually contain files"""
   580     directories or junction points if they actually contain files"""
   532     if listdir(name):
   581     if listdir(name):
   542             os.rmdir(head)
   591             os.rmdir(head)
   543         except (ValueError, OSError):
   592         except (ValueError, OSError):
   544             break
   593             break
   545         head, tail = os.path.split(head)
   594         head, tail = os.path.split(head)
   546 
   595 
       
   596 
   547 def rename(src, dst):
   597 def rename(src, dst):
   548     '''atomically rename file src to dst, replacing dst if it exists'''
   598     '''atomically rename file src to dst, replacing dst if it exists'''
   549     try:
   599     try:
   550         os.rename(src, dst)
   600         os.rename(src, dst)
   551     except OSError as e:
   601     except OSError as e:
   552         if e.errno != errno.EEXIST:
   602         if e.errno != errno.EEXIST:
   553             raise
   603             raise
   554         unlink(dst)
   604         unlink(dst)
   555         os.rename(src, dst)
   605         os.rename(src, dst)
   556 
   606 
       
   607 
   557 def gethgcmd():
   608 def gethgcmd():
   558     return [encoding.strtolocal(arg) for arg in [sys.executable] + sys.argv[:1]]
   609     return [encoding.strtolocal(arg) for arg in [sys.executable] + sys.argv[:1]]
       
   610 
   559 
   611 
   560 def groupmembers(name):
   612 def groupmembers(name):
   561     # Don't support groups on Windows for now
   613     # Don't support groups on Windows for now
   562     raise KeyError
   614     raise KeyError
   563 
   615 
       
   616 
   564 def isexec(f):
   617 def isexec(f):
   565     return False
   618     return False
       
   619 
   566 
   620 
   567 class cachestat(object):
   621 class cachestat(object):
   568     def __init__(self, path):
   622     def __init__(self, path):
   569         pass
   623         pass
   570 
   624 
   571     def cacheable(self):
   625     def cacheable(self):
   572         return False
   626         return False
       
   627 
   573 
   628 
   574 def lookupreg(key, valname=None, scope=None):
   629 def lookupreg(key, valname=None, scope=None):
   575     ''' Look up a key/value name in the Windows registry.
   630     ''' Look up a key/value name in the Windows registry.
   576 
   631 
   577     valname: value name. If unspecified, the default value for the key
   632     valname: value name. If unspecified, the default value for the key
   592                 # never let a Unicode string escape into the wild
   647                 # never let a Unicode string escape into the wild
   593                 return encoding.unitolocal(val)
   648                 return encoding.unitolocal(val)
   594         except EnvironmentError:
   649         except EnvironmentError:
   595             pass
   650             pass
   596 
   651 
       
   652 
   597 expandglobs = True
   653 expandglobs = True
       
   654 
   598 
   655 
   599 def statislink(st):
   656 def statislink(st):
   600     '''check whether a stat result is a symlink'''
   657     '''check whether a stat result is a symlink'''
   601     return False
   658     return False
   602 
   659 
       
   660 
   603 def statisexec(st):
   661 def statisexec(st):
   604     '''check whether a stat result is an executable file'''
   662     '''check whether a stat result is an executable file'''
   605     return False
   663     return False
   606 
   664 
       
   665 
   607 def poll(fds):
   666 def poll(fds):
   608     # see posix.py for description
   667     # see posix.py for description
   609     raise NotImplementedError()
   668     raise NotImplementedError()
       
   669 
   610 
   670 
   611 def readpipe(pipe):
   671 def readpipe(pipe):
   612     """Read all available data from a pipe."""
   672     """Read all available data from a pipe."""
   613     chunks = []
   673     chunks = []
   614     while True:
   674     while True:
   621             break
   681             break
   622         chunks.append(s)
   682         chunks.append(s)
   623 
   683 
   624     return ''.join(chunks)
   684     return ''.join(chunks)
   625 
   685 
       
   686 
   626 def bindunixsocket(sock, path):
   687 def bindunixsocket(sock, path):
   627     raise NotImplementedError(r'unsupported platform')
   688     raise NotImplementedError(r'unsupported platform')