##// END OF EJS Templates
phabricator: fix a phabsend crash when processing a renamed binary...
phabricator: fix a phabsend crash when processing a renamed binary This was a trivial fix, and some more tests are added to cover binary files. Since the old filecontext is passed in, the old name is still available. But I noticed some weirdness around what it marked as binary and not, and what is viewable in Phabricator. Those things have been flagged, and will probably take some digging. Differential Revision: https://phab.mercurial-scm.org/D8133

File last commit:

r44787:a0ec05d9 default
r44848:d1177d39 stable
Show More
posix.py
780 lines | 22.9 KiB | text/x-python | PythonLexer
Martin Geisler
put license and copyright info into comment blocks
r8226 # 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
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Gregory Szorc
posix: use absolute_import
r25967 from __future__ import absolute_import
import errno
import fcntl
import getpass
import grp
import os
import pwd
import re
Pierre-Yves David
util: add a simple poll utility...
r25420 import select
Gregory Szorc
posix: use absolute_import
r25967 import stat
import sys
import tempfile
import unicodedata
from .i18n import _
Gregory Szorc
py3: manually import getattr where it is needed...
r43359 from .pycompat import (
getattr,
open,
)
Gregory Szorc
posix: use absolute_import
r25967 from . import (
encoding,
Augie Fackler
ssh: ban any username@host or host that starts with - (SEC)...
r33724 error,
Matt Harbison
util: move getfstype() to the platform modules...
r35527 policy,
Pulkit Goyal
py3: replace os.pathsep with pycompat.ospathsep...
r30612 pycompat,
Gregory Szorc
posix: use absolute_import
r25967 )
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 osutil = policy.importmod('osutil')
Matt Harbison
util: move getfstype() to the platform modules...
r35527
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 normpath = os.path.normpath
samestat = os.path.samestat
Augie Fackler
posix: work around "posix" systems without os.link available (issue4974)...
r27236 try:
oslink = os.link
except AttributeError:
# Some platforms build Python without os.link on systems that are
# vaguely unix-like but don't have hardlink support. For those
# poor souls, just say we tried and that it failed so we fall back
# to copies.
def oslink(src, dst):
Augie Fackler
formatting: blacken the codebase...
r43346 raise OSError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 errno.EINVAL, b'hardlinks not supported: %s to %s' % (src, dst)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Matt Harbison
py3: convert os.readlink() path to native strings on Windows...
r39940 readlink = os.readlink
Adrian Buehlmann
reintroduces util.unlink, for POSIX and Windows....
r13280 unlink = os.unlink
Adrian Buehlmann
util: move rename into posix.py and windows.py
r9549 rename = os.rename
FUJIWARA Katsunori
util: add removedirs as platform depending function...
r24692 removedirs = os.removedirs
Matt Mackall
cmdutils: Take over glob expansion duties from util
r8614 expandglobs = False
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
umask = os.umask(0)
os.umask(umask)
Augie Fackler
posix: always seek to EOF when opening a file in append mode...
r42778 if not pycompat.ispy3:
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 def posixfile(name, mode='r', buffering=-1):
Augie Fackler
posix: always seek to EOF when opening a file in append mode...
r42778 fp = open(name, mode=mode, buffering=buffering)
# The position when opening in append mode is implementation defined, so
# make it consistent by always seeking to the end.
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 if 'a' in mode:
Augie Fackler
posix: always seek to EOF when opening a file in append mode...
r42778 fp.seek(0, os.SEEK_END)
return fp
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
posix: always seek to EOF when opening a file in append mode...
r42778 else:
# The underlying file object seeks as required in Python 3:
# https://github.com/python/cpython/blob/v3.7.3/Modules/_io/fileio.c#L474
posixfile = open
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
util: implement a faster os.path.split for posix systems...
r17560 def split(p):
Remy Blank
posix: fix split() for the case where the path is at the root of the filesystem...
r18288 '''Same as posixpath.split, but faster
>>> import posixpath
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> for f in [b'/absolute/path/to/file',
... b'relative/path/to/file',
... b'file_alone',
... b'path/to/directory/',
... b'/multiple/path//separators',
... b'/file_at_root',
... b'///multiple_leading_separators_at_root',
... b'']:
Remy Blank
posix: fix split() for the case where the path is at the root of the filesystem...
r18288 ... assert split(f) == posixpath.split(f), f
'''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ht = p.rsplit(b'/', 1)
Bryan O'Sullivan
util: implement a faster os.path.split for posix systems...
r17560 if len(ht) == 1:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'', p
nh = ht[0].rstrip(b'/')
Bryan O'Sullivan
util: implement a faster os.path.split for posix systems...
r17560 if nh:
return nh, ht[1]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return ht[0] + b'/', ht[1]
Bryan O'Sullivan
util: implement a faster os.path.split for posix systems...
r17560
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def openhardlinks():
'''return true if it is safe to hold open file handles to hardlinks'''
return True
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
port win32.py to using the Python ctypes library...
r13375 def nlinks(name):
'''return number of hardlinks for the given file'''
return os.lstat(name).st_nlink
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
rename util.parse_patch_output to parsepatchoutput
r14231 def parsepatchoutput(output_line):
timeless
Generally replace "file name" with "filename" in help and comments.
r8761 """parses the output produced by patch and returns the filename"""
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 pf = output_line[14:]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if pycompat.sysplatform == b'OpenVMS':
if pf[0] == b'`':
Augie Fackler
formatting: blacken the codebase...
r43346 pf = pf[1:-1] # Remove the quotes
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if pf.startswith(b"'") and pf.endswith(b"'") and b" " in pf:
Augie Fackler
formatting: blacken the codebase...
r43346 pf = pf[1:-1] # Remove the quotes
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return pf
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def sshargs(sshcmd, host, user, port):
'''Build argument list for ssh'''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 args = user and (b"%s@%s" % (user, host)) or host
if b'-' in args[:1]:
Augie Fackler
ssh: ban any username@host or host that starts with - (SEC)...
r33724 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'illegal ssh hostname or username starting with -: %s') % args
Augie Fackler
formatting: blacken the codebase...
r43346 )
Jun Wu
ssh: quote parameters using shellquote (SEC)...
r33732 args = shellquote(args)
if port:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 args = b'-p %s %s' % (shellquote(port), args)
Jun Wu
ssh: quote parameters using shellquote (SEC)...
r33732 return args
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
rename util.is_exec to isexec
r14273 def isexec(f):
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 """check whether a file is executable"""
Augie Fackler
formatting: blacken the codebase...
r43346 return os.lstat(f).st_mode & 0o100 != 0
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Adrian Buehlmann
rename util.set_flags to setflags
r14232 def setflags(f, l, x):
Koen Van Hoof
chmod: create a new file when flags are set on a hardlinked file...
r32721 st = os.lstat(f)
s = st.st_mode
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if l:
if not stat.S_ISLNK(s):
# switch file to link
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fp = open(f, b'rb')
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 data = fp.read()
fp.close()
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(f)
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 try:
os.symlink(data, f)
Idan Kamara
eliminate various naked except clauses
r14004 except OSError:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 # failed to make a link, rewrite file
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fp = open(f, b"wb")
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 fp.write(data)
fp.close()
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 # no chmod needed at this point
return
if stat.S_ISLNK(s):
# switch link to file
data = os.readlink(f)
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(f)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fp = open(f, b"wb")
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 fp.write(data)
fp.close()
Augie Fackler
formatting: blacken the codebase...
r43346 s = 0o666 & ~umask # avoid restatting for chmod
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 sx = s & 0o100
Koen Van Hoof
chmod: create a new file when flags are set on a hardlinked file...
r32721 if st.st_nlink > 1 and bool(x) != bool(sx):
# the file is a hardlink, break it
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with open(f, b"rb") as fp:
Koen Van Hoof
chmod: create a new file when flags are set on a hardlinked file...
r32721 data = fp.read()
unlink(f)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with open(f, b"wb") as fp:
Koen Van Hoof
chmod: create a new file when flags are set on a hardlinked file...
r32721 fp.write(data)
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if x and not sx:
# Turn on +x for every +r bit when making a file executable
# and obey umask.
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 os.chmod(f, s | (s & 0o444) >> 2 & ~umask)
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 elif not x and sx:
# Turn off all +x bits
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 os.chmod(f, s & 0o666)
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
update: fix edge-case with update.atomic-file and read-only files...
r41325 def copymode(src, dst, mode=None, enforcewritable=False):
Adrian Buehlmann
util: move copymode into posix.py and windows.py...
r15011 '''Copy the file mode from the file at path src to dst.
If src doesn't exist, we're using mode instead. If mode is None, we're
using umask.'''
try:
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 st_mode = os.lstat(src).st_mode & 0o777
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as inst:
Adrian Buehlmann
util: move copymode into posix.py and windows.py...
r15011 if inst.errno != errno.ENOENT:
raise
st_mode = mode
if st_mode is None:
st_mode = ~umask
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 st_mode &= 0o666
Boris Feld
update: fix edge-case with update.atomic-file and read-only files...
r41325
new_mode = st_mode
if enforcewritable:
new_mode |= stat.S_IWUSR
os.chmod(dst, new_mode)
Adrian Buehlmann
util: move copymode into posix.py and windows.py...
r15011
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
util: move checkexec() to posix.py and return False on Windows
r13879 def checkexec(path):
"""
Check whether the given path is on a filesystem with UNIX-like exec flags
Requires a directory (like /foo/.hg)
"""
# VFAT on some Linux versions can flip mode but it doesn't persist
# a FS remount. Frequently we can detect it if files are created
# with exec bit on.
try:
EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 basedir = os.path.join(path, b'.hg')
cachedir = os.path.join(basedir, b'wcache')
storedir = os.path.join(basedir, b'store')
Boris Feld
checkexec: create destination directory if necessary...
r40703 if not os.path.exists(cachedir):
try:
# we want to create the 'cache' directory, not the '.hg' one.
# Automatically creating '.hg' directory could silently spawn
# invalid Mercurial repositories. That seems like a bad idea.
os.mkdir(cachedir)
if os.path.exists(storedir):
copymode(storedir, cachedir)
else:
copymode(basedir, cachedir)
except (IOError, OSError):
# we other fallback logic triggers
pass
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446 if os.path.isdir(cachedir):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 checkisexec = os.path.join(cachedir, b'checkisexec')
checknoexec = os.path.join(cachedir, b'checknoexec')
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446
try:
m = os.stat(checkisexec).st_mode
except OSError as e:
if e.errno != errno.ENOENT:
raise
# checkisexec does not exist - fall through ...
else:
# checkisexec exists, check if it actually is exec
if m & EXECFLAGS != 0:
# ensure checkisexec exists, check it isn't exec
try:
m = os.stat(checknoexec).st_mode
except OSError as e:
if e.errno != errno.ENOENT:
raise
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 open(checknoexec, b'w').close() # might fail
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446 m = os.stat(checknoexec).st_mode
if m & EXECFLAGS == 0:
# check-exec is exec and check-no-exec is not exec
return True
# checknoexec exists but is exec - delete it
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(checknoexec)
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446 # checkisexec exists but is not exec - delete it
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(checkisexec)
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446
# check using one file, leave it as checkisexec
checkdir = cachedir
else:
# check directly in path and don't leave checkisexec behind
checkdir = path
checkisexec = None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fh, fn = pycompat.mkstemp(dir=checkdir, prefix=b'hg-checkexec-')
Adrian Buehlmann
util: move checkexec() to posix.py and return False on Windows
r13879 try:
os.close(fh)
Mads Kiilerich
posix: simplify checkexec check...
r30445 m = os.stat(fn).st_mode
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446 if m & EXECFLAGS == 0:
os.chmod(fn, m & 0o777 | EXECFLAGS)
if os.stat(fn).st_mode & EXECFLAGS != 0:
if checkisexec is not None:
os.rename(fn, checkisexec)
fn = None
return True
Adrian Buehlmann
util: move checkexec() to posix.py and return False on Windows
r13879 finally:
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446 if fn is not None:
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(fn)
Adrian Buehlmann
util: move checkexec() to posix.py and return False on Windows
r13879 except (IOError, OSError):
# we don't care, the user probably won't be able to commit anyway
return False
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
util: move checklink() to posix.py and return False on Windows...
r13890 def checklink(path):
"""check whether the given path is on a symlink-capable filesystem"""
# mktemp is not racy because symlink creation will fail if the
# file already exists
Matt Mackall
posix: retry on symlink race in checklink...
r26883 while True:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cachedir = os.path.join(path, b'.hg', b'wcache')
checklink = os.path.join(cachedir, b'checklink')
Mads Kiilerich
posix: give checklink a fast path that cache the check file and is read only...
r30448 # try fast path, read only
if os.path.islink(checklink):
return True
Mads Kiilerich
posix: move checklink test file to .hg/cache...
r30447 if os.path.isdir(cachedir):
checkdir = cachedir
else:
checkdir = path
cachedir = None
Augie Fackler
formatting: blacken the codebase...
r43346 name = tempfile.mktemp(
dir=pycompat.fsdecode(checkdir), prefix=r'checklink-'
)
Augie Fackler
posix: tiptoe around tempfile module more delicately...
r31506 name = pycompat.fsencode(name)
Augie Fackler
checklink: always close the NamedTemporaryFile...
r22946 try:
Martijn Pieters
posix: give the cached symlink a real target...
r30555 fd = None
if cachedir is None:
Augie Fackler
formatting: blacken the codebase...
r43346 fd = pycompat.namedtempfile(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 dir=checkdir, prefix=b'hg-checklink-'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Yuya Nishihara
py3: wrap tempfile.NamedTemporaryFile() to return bytes fp.name...
r38184 target = os.path.basename(fd.name)
Martijn Pieters
posix: give the cached symlink a real target...
r30555 else:
# create a fixed file to link to; doesn't matter if it
# already exists.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 target = b'checklink-target'
Augie Fackler
checklink: degrade gracefully on posix when fs is readonly (issue5511)...
r32393 try:
Augie Fackler
cleanup: fix some latent open(path).read() et al calls we previously missed...
r36966 fullpath = os.path.join(cachedir, target)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 open(fullpath, b'w').close()
Augie Fackler
checklink: degrade gracefully on posix when fs is readonly (issue5511)...
r32393 except IOError as inst:
Augie Fackler
posix: add a pytype suppression...
r43778 if (
inst[0] # pytype: disable=unsupported-operands
== errno.EACCES
):
Augie Fackler
checklink: degrade gracefully on posix when fs is readonly (issue5511)...
r32393 # If we can't write to cachedir, just pretend
# that the fs is readonly and by association
# that the fs won't support symlinks. This
# seems like the least dangerous way to avoid
# data loss.
return False
raise
Matt Mackall
posix: retry on symlink race in checklink...
r26883 try:
Martijn Pieters
posix: give the cached symlink a real target...
r30555 os.symlink(target, name)
Mads Kiilerich
posix: give checklink a fast path that cache the check file and is read only...
r30448 if cachedir is None:
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(name)
Mads Kiilerich
posix: give checklink a fast path that cache the check file and is read only...
r30448 else:
try:
os.rename(name, checklink)
except OSError:
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(name)
Matt Mackall
posix: retry on symlink race in checklink...
r26883 return True
except OSError as inst:
# link creation might race, try again
Augie Fackler
posix: use inst.errno instead of inst[0] on OSError instances...
r37953 if inst.errno == errno.EEXIST:
Matt Mackall
posix: retry on symlink race in checklink...
r26883 continue
Matt Mackall
posix: fix test-permissions regression
r26889 raise
Matt Mackall
posix: retry on symlink race in checklink...
r26883 finally:
Martijn Pieters
posix: give the cached symlink a real target...
r30555 if fd is not None:
fd.close()
Matt Mackall
posix: retry on symlink race in checklink...
r26883 except AttributeError:
return False
Matt Mackall
posix: fix test-permissions regression
r26889 except OSError as inst:
# sshfs might report failure while successfully creating the link
Augie Fackler
posix: use inst.errno instead of inst[0] on OSError instances...
r37953 if inst.errno == errno.EIO and os.path.exists(name):
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(name)
Matt Mackall
posix: fix test-permissions regression
r26889 return False
Adrian Buehlmann
util: move checklink() to posix.py and return False on Windows...
r13890
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 def checkosfilename(path):
'''Check that the base-relative path is a valid filename on this platform.
Returns None if the path is ok, or a UI string describing the problem.'''
Augie Fackler
formatting: blacken the codebase...
r43346 return None # on posix platforms, every path is ok
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916
Matt Harbison
util: add a function to show the mount point of the filesystem...
r35531 def getfsmountpoint(dirpath):
'''Get the filesystem mount point from a directory (best-effort)
Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc.
'''
return getattr(osutil, 'getfsmountpoint', lambda x: None)(dirpath)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
util: move getfstype() to the platform modules...
r35527 def getfstype(dirpath):
'''Get the filesystem type name from a directory (best-effort)
Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc.
'''
return getattr(osutil, 'getfstype', lambda x: None)(dirpath)
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
rename util.set_binary to setbinary
r14233 def setbinary(fd):
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 pass
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def pconvert(path):
return path
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def localpath(path):
return path
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
Add support for relinking on Windows....
r10218 def samefile(fpath1, fpath2):
"""Returns whether path1 and path2 refer to the same file. This is only
guaranteed to work for files, not directories."""
return os.path.samefile(fpath1, fpath2)
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
Add support for relinking on Windows....
r10218 def samedevice(fpath1, fpath2):
"""Returns whether fpath1 and fpath2 are on the same device. This is only
guaranteed to work for files, not directories."""
st1 = os.lstat(fpath1)
st2 = os.lstat(fpath2)
return st1.st_dev == st2.st_dev
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
dirstate: fix case-folding identity for traditional Unix...
r15488 # os.path.normcase is a no-op, which doesn't help us on non-native filesystems
def normcase(path):
return path.lower()
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
posix: define normcase spec and fallback...
r24594 # what normcase does to ASCII strings
normcasespec = encoding.normcasespecs.lower
# fallback normcase function for non-ASCII strings
normcasefallback = normcase
Jun Wu
codemod: use pycompat.isdarwin...
r34648 if pycompat.isdarwin:
Matt Mackall
posix: add extended support for OS X path folding...
r15551
def normcase(path):
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 '''
Normalize a filename for OS X-compatible comparison:
- escape-encode invalid characters
- decompose to NFD
- lowercase
Augie Fackler
darwin: omit ignorable codepoints when normcase()ing a file path...
r23597 - omit ignored characters [200c-200f, 202a-202e, 206a-206f,feff]
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> normcase(b'UPPER')
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 'upper'
Augie Fackler
posix: fix HFS+ normcase doctest to produce valid bytes literals in Python 3...
r34196 >>> normcase(b'Caf\\xc3\\xa9')
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 'cafe\\xcc\\x81'
Augie Fackler
posix: fix HFS+ normcase doctest to produce valid bytes literals in Python 3...
r34196 >>> normcase(b'\\xc3\\x89')
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 'e\\xcc\\x81'
Augie Fackler
posix: fix HFS+ normcase doctest to produce valid bytes literals in Python 3...
r34196 >>> normcase(b'\\xb8\\xca\\xc3\\xca\\xbe\\xc8.JPG') # issue3918
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 '%b8%ca%c3\\xca\\xbe%c8.jpg'
'''
Matt Mackall
posix: add extended support for OS X path folding...
r15551 try:
Siddharth Agarwal
normcase: for darwin, use fast ASCII lower...
r22781 return encoding.asciilower(path) # exception for non-ASCII
Mads Kiilerich
OS X: try cheap ascii .lower() in normcase before making full unicode dance...
r18501 except UnicodeDecodeError:
Siddharth Agarwal
darwin: define normcase spec and fallback...
r24595 return normcasefallback(path)
normcasespec = encoding.normcasespecs.lower
def normcasefallback(path):
Mads Kiilerich
OS X: try cheap ascii .lower() in normcase before making full unicode dance...
r18501 try:
Matt Mackall
posix: add extended support for OS X path folding...
r15551 u = path.decode('utf-8')
except UnicodeDecodeError:
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 # OS X percent-encodes any bytes that aren't valid utf-8
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s = b''
Matt Mackall
posix: use getutf8char to handle OS X filename percent-escaping...
r26876 pos = 0
Matt Mackall
mac: fix percent-encoding of non-utf-8 characters (issue4999)
r27380 l = len(path)
Matt Mackall
posix: use getutf8char to handle OS X filename percent-escaping...
r26876 while pos < l:
try:
c = encoding.getutf8char(path, pos)
pos += len(c)
except ValueError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 c = b'%%%02X' % ord(path[pos : pos + 1])
Matt Mackall
posix: use getutf8char to handle OS X filename percent-escaping...
r26876 pos += 1
s += c
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131
Matt Mackall
posix: add extended support for OS X path folding...
r15551 u = s.decode('utf-8')
# Decompose then lowercase (HFS+ technote specifies lower)
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 enc = unicodedata.normalize('NFD', u).lower().encode('utf-8')
Augie Fackler
darwin: omit ignorable codepoints when normcase()ing a file path...
r23597 # drop HFS+ ignored characters
return encoding.hfsignoreclean(enc)
Matt Mackall
posix: add extended support for OS X path folding...
r15551
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if pycompat.sysplatform == b'cygwin':
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711 # workaround for cygwin, in which mount point part of path is
# treated as case sensitive, even though underlying NTFS is case
# insensitive.
# default mount points
Augie Fackler
formatting: blacken the codebase...
r43346 cygwinmountpoints = sorted(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 [b"/usr/bin", b"/usr/lib", b"/cygdrive",], reverse=True
Augie Fackler
formatting: blacken the codebase...
r43346 )
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711
# use upper-ing as normcase as same as NTFS workaround
def normcase(path):
pathlen = len(path)
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 2 of 4)...
r30614 if (pathlen == 0) or (path[0] != pycompat.ossep):
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711 # treat as relative
Adrian Buehlmann
util, posix: eliminate encodinglower and encodingupper...
r17203 return encoding.upper(path)
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711
# to preserve case of mountpoint part
for mp in cygwinmountpoints:
if not path.startswith(mp):
continue
mplen = len(mp)
Augie Fackler
formatting: blacken the codebase...
r43346 if mplen == pathlen: # mount point itself
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711 return mp
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 2 of 4)...
r30614 if path[mplen] == pycompat.ossep:
Adrian Buehlmann
util, posix: eliminate encodinglower and encodingupper...
r17203 return mp + encoding.upper(path[mplen:])
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711
Adrian Buehlmann
util, posix: eliminate encodinglower and encodingupper...
r17203 return encoding.upper(path)
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711
Siddharth Agarwal
cygwin: define normcase spec and fallback...
r24596 normcasespec = encoding.normcasespecs.other
normcasefallback = normcase
A. S. Budden
posix: ignore execution bit in cygwin (issue3301)
r16240 # Cygwin translates native ACLs to POSIX permissions,
# but these translations are not supported by native
# tools, so the exec bit tends to be set erroneously.
# Therefore, disable executable bit access on Cygwin.
def checkexec(path):
return False
Matt Mackall
posix: disable cygwin's symlink emulation
r16241 # Similarly, Cygwin's symlink emulation is likely to create
# problems when Mercurial is used from both Cygwin and native
# Windows, with other native tools, or on shared volumes
def checklink(path):
return False
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
posix: quote the specified string only when it may have to be quoted...
r23683 _needsshellquote = None
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def shellquote(s):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if pycompat.sysplatform == b'OpenVMS':
return b'"%s"' % s
FUJIWARA Katsunori
posix: quote the specified string only when it may have to be quoted...
r23683 global _needsshellquote
if _needsshellquote is None:
Pulkit Goyal
py3: make the regular expression bytes to prevent TypeError
r31491 _needsshellquote = re.compile(br'[^a-zA-Z0-9._/+-]').search
Yuya Nishihara
shellquote: fix missing quotes for empty string...
r24108 if s and not _needsshellquote(s):
FUJIWARA Katsunori
posix: quote the specified string only when it may have to be quoted...
r23683 # "s" shouldn't have to be quoted
return s
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b"'%s'" % s.replace(b"'", b"'\\''")
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
util: factor out shellsplit() function...
r36433 def shellsplit(s):
"""Parse a command string in POSIX shell way (best-effort)"""
return pycompat.shlexsplit(s, posix=True)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def quotecommand(cmd):
return cmd
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def testpid(pid):
'''return False if pid dead, True if running or not sure'''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if pycompat.sysplatform == b'OpenVMS':
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return True
try:
os.kill(pid, 0)
return True
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as inst:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return inst.errno != errno.ESRCH
Augie Fackler
formatting: blacken the codebase...
r43346
Martin Geisler
posix: do not use fstat in isowner...
r8657 def isowner(st):
"""Return True if the stat object st is from the current user."""
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return st.st_uid == os.getuid()
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
rename util.find_exe to findexe
r14271 def findexe(command):
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 '''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.'''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if pycompat.sysplatform == b'OpenVMS':
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return command
def findexisting(executable):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'Will return executable if existing file'
Marc-Antoine Ruel
posix: fix findexe() to check for file type and access
r15499 if os.path.isfile(executable) and os.access(executable, os.X_OK):
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return executable
return None
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 2 of 4)...
r30614 if pycompat.ossep in command:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return findexisting(command)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if pycompat.sysplatform == b'plan9':
return findexisting(os.path.join(b'/bin', command))
Steven Stallion
plan9: initial support for plan 9 from bell labs...
r16383
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for path in encoding.environ.get(b'PATH', b'').split(pycompat.ospathsep):
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 executable = findexisting(os.path.join(path, command))
if executable is not None:
Marc-Antoine Ruel
posix: fix findexe() to check for file type and access
r15499 return executable
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return None
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
rename util.set_signal_handler to setsignalhandler
r14237 def setsignalhandler():
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 pass
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
cleanup: use set literals...
r32291 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK}
Bryan O'Sullivan
dirstate: move file type filtering to its source...
r18017
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def statfiles(files):
Bryan O'Sullivan
dirstate: move file type filtering to its source...
r18017 '''Stat each file in files. Yield each stat, or None if a file does not
exist or has a type we don't care about.'''
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 lstat = os.lstat
Bryan O'Sullivan
dirstate: move file type filtering to its source...
r18017 getkind = stat.S_IFMT
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 for nf in files:
try:
st = lstat(nf)
Bryan O'Sullivan
dirstate: move file type filtering to its source...
r18017 if getkind(st.st_mode) not in _wantedkinds:
st = None
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as err:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
raise
st = None
yield st
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def getuser():
'''return name of current user'''
Pulkit Goyal
py3: make posix.getuser return a bytes
r32129 return pycompat.fsencode(getpass.getuser())
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 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:
Pulkit Goyal
py3: make sure util.username() always returns bytes...
r38271 return pycompat.fsencode(pwd.getpwuid(uid)[0])
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 except KeyError:
Pulkit Goyal
py3: make sure util.username() always returns bytes...
r38271 return b'%d' % uid
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 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:
Pulkit Goyal
py3: make sure return value of posix.groupname() is bytes...
r41993 return pycompat.fsencode(grp.getgrgid(gid)[0])
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 except KeyError:
Pulkit Goyal
py3: make sure return value of posix.groupname() is bytes...
r41993 return pycompat.bytestr(gid)
Patrick Mezard
serve: add and use portable spawnvp replacement...
r10237
Augie Fackler
formatting: blacken the codebase...
r43346
Patrick Mezard
acl: grp module is not available on windows
r11138 def groupmembers(name):
"""Return the list of members of the group with the given
name, KeyError if the group does not exist.
"""
Pulkit Goyal
py3: do a fsdecode(), fsencode() dance in posix.py...
r41664 name = pycompat.fsdecode(name)
return pycompat.rapply(pycompat.fsencode, list(grp.getgrnam(name).gr_mem))
Patrick Mezard
acl: grp module is not available on windows
r11138
Augie Fackler
formatting: blacken the codebase...
r43346
Patrick Mezard
serve: add and use portable spawnvp replacement...
r10237 def spawndetached(args):
Augie Fackler
formatting: blacken the codebase...
r43346 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0), args[0], args)
Patrick Mezard
serve: add and use portable spawnvp replacement...
r10237
Patrick Mezard
Find right hg command for detached process...
r10239 def gethgcmd():
return sys.argv[:1]
Patrick Mezard
util: fix default termwidth() under Windows...
r11010
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
util: move "default" makedir to posix.py...
r14908 def makedir(path, notindexed):
os.mkdir(path)
Adrian Buehlmann
util: move "default" unlinkpath to posix.py...
r14909
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
util: move "default" lookupreg to posix.py...
r14910 def lookupreg(key, name=None, scope=None):
return None
Adrian Buehlmann
util: move "default" hidewindow to posix.py...
r14911
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
util: move "default" hidewindow to posix.py...
r14911 def hidewindow():
"""Hide current shell window.
Used to hide the window opened when starting asynchronous
child process under Windows, unneeded on other systems.
"""
pass
Adrian Buehlmann
util: eliminate wildcard imports
r14926
Augie Fackler
formatting: blacken the codebase...
r43346
Idan Kamara
posix, windows: introduce cachestat...
r14927 class cachestat(object):
def __init__(self, path):
self.stat = os.stat(path)
def cacheable(self):
return bool(self.stat.st_ino)
Martin Geisler
Use explicit integer division...
r15791 __hash__ = object.__hash__
Idan Kamara
posix, windows: introduce cachestat...
r14927 def __eq__(self, other):
try:
Siddharth Agarwal
posix: don't compare atime when determining if a file has changed...
r18442 # Only dev, ino, size, mtime and atime are likely to change. Out
# of these, we shouldn't compare atime but should compare the
# rest. However, one of the other fields changing indicates
# something fishy going on, so return False if anything but atime
# changes.
Augie Fackler
formatting: blacken the codebase...
r43346 return (
self.stat.st_mode == other.stat.st_mode
and self.stat.st_ino == other.stat.st_ino
and self.stat.st_dev == other.stat.st_dev
and self.stat.st_nlink == other.stat.st_nlink
and self.stat.st_uid == other.stat.st_uid
and self.stat.st_gid == other.stat.st_gid
and self.stat.st_size == other.stat.st_size
and self.stat[stat.ST_MTIME] == other.stat[stat.ST_MTIME]
and self.stat[stat.ST_CTIME] == other.stat[stat.ST_CTIME]
)
Idan Kamara
posix, windows: introduce cachestat...
r14927 except AttributeError:
return False
def __ne__(self, other):
return not self == other
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
util: add functions to check symlink/exec bits...
r18868 def statislink(st):
'''check whether a stat result is a symlink'''
return st and stat.S_ISLNK(st.st_mode)
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
util: add functions to check symlink/exec bits...
r18868 def statisexec(st):
'''check whether a stat result is an executable file'''
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 return st and (st.st_mode & 0o100 != 0)
Gregory Szorc
platform: implement readpipe()...
r22245
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
util: add a simple poll utility...
r25420 def poll(fds):
"""block until something happens on any file descriptor
This is a generic helper that will check for any activity
(read, write. exception) and return the list of touched files.
In unsupported cases, it will raise a NotImplementedError"""
try:
Yuya Nishihara
posix: make poll() restart on interruption by signal (issue5452)...
r30654 while True:
try:
res = select.select(fds, fds, fds)
break
except select.error as inst:
if inst.args[0] == errno.EINTR:
continue
raise
Augie Fackler
formatting: blacken the codebase...
r43346 except ValueError: # out of range file descriptor
Pierre-Yves David
util: add a simple poll utility...
r25420 raise NotImplementedError()
return sorted(list(set(sum(res, []))))
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
platform: implement readpipe()...
r22245 def readpipe(pipe):
"""Read all available data from a pipe."""
Gregory Szorc
posix: implement readpipe using non-blocking I/O (issue4336)...
r22246 # We can't fstat() a pipe because Linux will always report 0.
# So, we set the pipe to non-blocking mode and read everything
# that's available.
flags = fcntl.fcntl(pipe, fcntl.F_GETFL)
flags |= os.O_NONBLOCK
oldflags = fcntl.fcntl(pipe, fcntl.F_SETFL, flags)
Gregory Szorc
platform: implement readpipe()...
r22245
Gregory Szorc
posix: implement readpipe using non-blocking I/O (issue4336)...
r22246 try:
chunks = []
while True:
try:
s = pipe.read()
if not s:
break
chunks.append(s)
except IOError:
break
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''.join(chunks)
Gregory Szorc
posix: implement readpipe using non-blocking I/O (issue4336)...
r22246 finally:
fcntl.fcntl(pipe, fcntl.F_SETFL, oldflags)
Yuya Nishihara
chgserver: extract utility to bind unix domain socket to long path...
r29530
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
chgserver: extract utility to bind unix domain socket to long path...
r29530 def bindunixsocket(sock, path):
"""Bind the UNIX domain socket to the specified path"""
# use relative path instead of full path at bind() if possible, since
# AF_UNIX path has very small length limit (107 chars) on common
# platforms (see sys/un.h)
dirname, basename = os.path.split(path)
bakwdfd = None
if dirname:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 bakwdfd = os.open(b'.', os.O_DIRECTORY)
Yuya Nishihara
chgserver: extract utility to bind unix domain socket to long path...
r29530 os.chdir(dirname)
sock.bind(basename)
if bakwdfd:
os.fchdir(bakwdfd)
os.close(bakwdfd)