windows: check target type before actual unlinking to follow POSIX semantics
Creation and writing into target file via vfs (a.k.a opener) is done
after "unlink()" target file, if it exists.
For example, it is assumed that the revision X consists of file 'A',
and the revision Y consists of file 'A/B'. Merging revision X into Y
tries to "unlink()" on directory 'A' of 'A/B', before creation of file
'A'.
On POSIX environment, directories should be removed by "rmdir(2)", and
"unlink(2)" on directories fails. "unlink()" of Mercurial (and Python)
uses "unlink(2)" directly, so unlinking in the merge case above would
fail.
In the other hand, on Windows environment, "unlink()" of Mercurial
tries to rename before actual unlinking, to follow POSIX semantics:
already opened file can be unlinked safely.
This causes unexpected success in unlinking in the merge case above,
even though directory 'A' is renamed to another. This confuses users.
This patch checks whether target is directory or not before renaming,
and raises IOError(errno.EPERM) if so, to follow POSIX semantics.
import sys, os
import osutil
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 systemrcpath():
path = []
if sys.platform == 'plan9':
root = 'lib/mercurial'
else:
root = 'etc/mercurial'
# old mod_python does not set sys.argv
if len(getattr(sys, 'argv', [])) > 0:
p = os.path.dirname(os.path.dirname(sys.argv[0]))
path.extend(_rcfiles(os.path.join(p, root)))
path.extend(_rcfiles('/' + root))
return path
def userrcpath():
if sys.platform == 'plan9':
return [os.environ['home'] + '/lib/hgrc']
else:
return [os.path.expanduser('~/.hgrc')]