[PATCH 1 of 3 STABLE] util: add utility function to skip avoiding file stat ambiguity if EPERM

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Sat Nov 12 16:16:08 EST 2016

# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1478984783 -32400
#      Sun Nov 13 06:06:23 2016 +0900
# Branch stable
# Node ID b496a464399cb68628b09e52aa8cf379c98428e6
# Parent  4ed8bb8a153f91420777d98dea10ebbcd403a375
util: add utility function to skip avoiding file stat ambiguity if EPERM

Now, advancing stat.st_mtime by os.utime() is used to avoid file stat
ambiguity. But according to POSIX specification, utime(2) with an
explicit time information is permitted only for a process with:

  - the effective user ID equal to the user ID of the file, or
  - appropriate privileges


Therefore, just having group write access to a file causes EPERM at
applying os.utime() on it (e.g. working on the repository shared by
group access permission).

This patch adds class filestat utility function avoidamgig() to avoid
file stat ambiguity but skip it if EPERM.

It is reasonable to always ignore EPERM, because utime(2) causes EPERM
only in the case described above (EACCES is used only for utime(2)
with NULL).

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -1497,6 +1497,24 @@ class filestat(object):
         except AttributeError:
             return False
+    def avoidambig(self, path, old):
+        """Change file stat of specified path to avoid ambiguity
+        'old' should be previous filestat of 'path'.
+        This skips avoiding ambiguity, if a process doesn't have
+        appropriate privileges for 'path'.
+        """
+        advanced = (old.stat.st_mtime + 1) & 0x7fffffff
+        try:
+            os.utime(path, (advanced, advanced))
+        except OSError as inst:
+            if inst.errno == errno.EPERM:
+                # utime() on the file created by another user causes EPERM,
+                # if a process doesn't have appropriate privileges
+                return
+            raise
     def __ne__(self, other):
         return not self == other

More information about the Mercurial-devel mailing list