localrepo: handle rename with hardlinks properly
In "aftertrans", we rename "journal.*" to "undo.*". We expect "journal.*"
files to disappear after renaming.
However, if "journal.foo" and "undo.foo" refer to a same file (hardlink),
rename may be a no-op, leaving both files on disk, according to Linux
manpage [1]:
If oldpath and newpath are existing hard links referring to the same
file, then rename() does nothing, and returns a suc‐ cess status.
The POSIX specification [2] is not very clear about what to do.
To be safe, remove "undo.*" before the rename so "journal.*" cannot be left
on disk.
[1]: http://man7.org/linux/man-pages/man2/rename.2.html
[2]: http://pubs.opengroup.org/onlinepubs/
9699919799/
--- a/mercurial/localrepo.py Wed Mar 01 18:21:06 2017 -0800
+++ b/mercurial/localrepo.py Thu Mar 02 21:49:30 2017 -0800
@@ -2012,6 +2012,14 @@
def a():
for vfs, src, dest in renamefiles:
try:
+ # if src and dest refer to a same file, vfs.rename is a no-op,
+ # leaving both src and dest on disk. delete dest to make sure
+ # the rename couldn't be such a no-op.
+ vfs.unlink(dest)
+ except OSError as ex:
+ if ex.errno != errno.ENOENT:
+ raise
+ try:
vfs.rename(src, dest)
except OSError: # journal file does not yet exist
pass