chmod: create a new file when flags are set on a hardlinked file
For performance reasons we have several repositories where the files in the working
directory of 1 repo are hardlinks to the files of the other repo
When an update in one repo results in a chmod of a such a file, the hardlink
has to be deleted and replaced by a regular file to make sure that the change
does not happen in the other repo
--- a/mercurial/posix.py Wed Jun 07 21:17:24 2017 -0700
+++ b/mercurial/posix.py Wed Apr 26 16:05:22 2017 +0200
@@ -98,7 +98,8 @@
return (os.lstat(f).st_mode & 0o100 != 0)
def setflags(f, l, x):
- s = os.lstat(f).st_mode
+ st = os.lstat(f)
+ s = st.st_mode
if l:
if not stat.S_ISLNK(s):
# switch file to link
@@ -125,6 +126,14 @@
s = 0o666 & ~umask # avoid restatting for chmod
sx = s & 0o100
+ if st.st_nlink > 1 and bool(x) != bool(sx):
+ # the file is a hardlink, break it
+ with open(f, "rb") as fp:
+ data = fp.read()
+ unlink(f)
+ with open(f, "wb") as fp:
+ fp.write(data)
+
if x and not sx:
# Turn on +x for every +r bit when making a file executable
# and obey umask.
--- a/tests/test-hardlinks.t Wed Jun 07 21:17:24 2017 -0700
+++ b/tests/test-hardlinks.t Wed Apr 26 16:05:22 2017 +0200
@@ -203,10 +203,18 @@
2 r2/.hg/store/fncache
#endif
+Create a file which exec permissions we will change
+ $ cd r3
+ $ echo "echo hello world" > f3
+ $ hg add f3
+ $ hg ci -mf3
+ $ cd ..
+
$ cd r3
$ hg tip --template '{rev}:{node|short}\n'
- 11:a6451b6bc41f
+ 12:d3b77733a28a
$ echo bla > f1
+ $ chmod +x f3
$ hg ci -m1
$ cd ..
@@ -241,6 +249,7 @@
2 r4/.hg/store/data/d1/f2.d
2 r4/.hg/store/data/d1/f2.i
2 r4/.hg/store/data/f1.i
+ 2 r4/.hg/store/data/f3.i
2 r4/.hg/store/fncache
2 r4/.hg/store/phaseroots
2 r4/.hg/store/undo
@@ -256,17 +265,18 @@
2 r4/d1/data1
2 r4/d1/f2
2 r4/f1
+ 2 r4/f3
+Update back to revision 12 in r4 should break hardlink of file f1 and f3:
#if hardlink-whitelisted
$ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/undo.dirstate
4 r4/.hg/undo.backup.dirstate
4 r4/.hg/undo.dirstate
#endif
-Update back to revision 11 in r4 should break hardlink of file f1:
- $ hg -R r4 up 11
- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R r4 up 12
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ nlinksdir r4
2 r4/.hg/00changelog.i
@@ -287,6 +297,7 @@
2 r4/.hg/store/data/d1/f2.d
2 r4/.hg/store/data/d1/f2.i
2 r4/.hg/store/data/f1.i
+ 2 r4/.hg/store/data/f3.i
2 r4/.hg/store/fncache
2 r4/.hg/store/phaseroots
2 r4/.hg/store/undo
@@ -302,6 +313,7 @@
2 r4/d1/data1
2 r4/d1/f2
1 r4/f1
+ 1 r4/f3
#if hardlink-whitelisted
$ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/undo.dirstate