From patchwork Thu Jun 29 16:53:13 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [6, of, 8] vfs: copy if EPERM to avoid file stat ambiguity forcibly at closing From: Katsunori FUJIWARA X-Patchwork-Id: 21829 Message-Id: To: mercurial-devel@mercurial-scm.org Date: Fri, 30 Jun 2017 01:53:13 +0900 # HG changeset patch # User FUJIWARA Katsunori # Date 1498754870 -32400 # Fri Jun 30 01:47:50 2017 +0900 # Node ID b833b68a2bb86c160ea25006f9f7216fce2921f5 # Parent e3a1739ee331b182c973ce679828b29e880db5ee vfs: copy if EPERM to avoid file stat ambiguity forcibly at closing Now, files (to be truncated) are opened with checkambig=True, only if localrepository caches it. Therefore, straightforward "copy if EPERM" is always reasonable to avoid file stat ambiguity at closing. This patch makes checkambigatclosing close wrapper copy the target file, and advance mtime on it after renaming, if EPERM. This can avoid file stat ambiguity, even if the target file is owned by another (see issue5418 and issue5584 for detail). This patch factors main logic out instead of changing checkambigatclosing._checkambig() directly, in order to reuse it. diff --git a/mercurial/vfs.py b/mercurial/vfs.py --- a/mercurial/vfs.py +++ b/mercurial/vfs.py @@ -22,6 +22,23 @@ from . import ( util, ) +def _avoidambig(path, oldstat): + """Avoid file stat ambiguity forcibly + + This function causes copying ``path`` file, if it is owned by + another (see issue5418 and issue5584 for detail). + """ + def checkandavoid(): + newstat = util.filestat.frompath(path) + # return whether file stat ambiguity is (already) avoided + return (not newstat.isambig(oldstat) or + newstat.avoidambig(path, oldstat)) + if not checkandavoid(): + # simply copy to change owner of path to get privilege to + # advance mtime (see issue5418) + util.rename(util.mktempcopy(path), path) + checkandavoid() + class abstractvfs(object): """Abstract base class; cannot be instantiated""" @@ -630,10 +647,7 @@ class checkambigatclosing(closewrapbase) def _checkambig(self): oldstat = self._oldstat if oldstat.stat: - newstat = util.filestat.frompath(self._origfh.name) - if newstat.isambig(oldstat): - # stat of changed file is ambiguous to original one - newstat.avoidambig(self._origfh.name, oldstat) + _avoidambig(self._origfh.name, oldstat) def __exit__(self, exc_type, exc_value, exc_tb): self._origfh.__exit__(exc_type, exc_value, exc_tb)