From patchwork Wed Jun 7 19:20:58 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [v3] chmod: create a new file when flags are set on a hardlinked file From: Koen Van Hoof X-Patchwork-Id: 21236 Message-Id: To: mercurial-devel@mercurial-scm.org Cc: koen.van_hoof@nokia.com Date: Wed, 07 Jun 2017 21:20:58 +0200 # HG changeset patch # User Koen Van Hoof # Date 1493215522 -7200 # Wed Apr 26 16:05:22 2017 +0200 # Node ID ed4818954e563f50068a3f948b826395bc342bff # Parent 3ef319e9505f376775c91b2ab7d89ac9ac4343e9 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 diff --git a/mercurial/posix.py b/mercurial/posix.py --- a/mercurial/posix.py +++ b/mercurial/posix.py @@ -98,7 +98,8 @@ def isexec(f): 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,13 @@ def setflags(f, l, x): 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,"r") as fp: + data=fp.read(); + unlink(f) + with open(f, "w") 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. diff --git a/tests/test-hardlinks.t b/tests/test-hardlinks.t --- a/tests/test-hardlinks.t +++ b/tests/test-hardlinks.t @@ -203,10 +203,18 @@ Committing a change to f1 in r1 must bre 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 @@ r4 has hardlinks in the working dir (not 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 @@ r4 has hardlinks in the working dir (not 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 @@ Update back to revision 11 in r4 should 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 @@ Update back to revision 11 in r4 should 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