changeset 5284:2570d2d4a268

caches: preserve permissions of top-level .hg When using hg on a shared filesystem on UNIX, cache files normally inherit the permissions of the .hg directory. This is most commonly used to ensure everything is writable by all users. The sqlite3 cache files don't have a way to directly set the permission, so check if a special mode is necessary and try to apply them to newly created database files.
author Joerg Sonnenberger <joerg@bec.de>
date Sun, 03 May 2020 01:01:19 +0200
parents 9e2f2557c42e
children 299d86c15b55
files hgext3rd/evolve/obsdiscovery.py hgext3rd/evolve/stablerangecache.py tests/test-sqlite3-permissions.t
diffstat 3 files changed, 53 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/hgext3rd/evolve/obsdiscovery.py	Sat May 02 23:31:31 2020 +0800
+++ b/hgext3rd/evolve/obsdiscovery.py	Sun May 03 01:01:19 2020 +0200
@@ -17,6 +17,7 @@
 
 import hashlib
 import heapq
+import os
 import sqlite3
 import struct
 import weakref
@@ -30,6 +31,7 @@
     node,
     obsolete,
     scmutil,
+    store,
     util,
 )
 from mercurial.i18n import _
@@ -343,6 +345,7 @@
         # cache status
         self._ondiskcachekey = None
         self._data = {}
+        self._createmode = store._calcmode(self._vfs)
 
     def clear(self, reset=False):
         super(_obshashcache, self).clear(reset=reset)
@@ -490,12 +493,19 @@
 
     def _db(self):
         try:
-            util.makedirs(self._vfs.dirname(self._path))
+            util.makedirs(self._vfs.dirname(self._path), self._createmode)
         except OSError:
             return None
+        if self._createmode is not None:
+            pre_existed = os.access(self._path, os.R_OK)
         con = sqlite3.connect(encoding.strfromlocal(self._path), timeout=30,
                               isolation_level=r"IMMEDIATE")
         con.text_factory = bytes
+        if self._createmode is not None and not pre_existed:
+            try:
+                os.chmod(self._path, self._createmode & 0o666)
+            except OSError:
+                pass
         return con
 
     @util.propertycache
@@ -599,6 +609,7 @@
             self._new.clear()
             self._valid = True
             self._ondiskcachekey = self._cachekey
+
 @eh.wrapfunction(obsolete.obsstore, '_addmarkers')
 def _addmarkers(orig, obsstore, *args, **kwargs):
     obsstore.rangeobshashcache.clear()
--- a/hgext3rd/evolve/stablerangecache.py	Sat May 02 23:31:31 2020 +0800
+++ b/hgext3rd/evolve/stablerangecache.py	Sun May 03 01:01:19 2020 +0200
@@ -9,6 +9,7 @@
 
 import abc
 import heapq
+import os
 import random
 import sqlite3
 import time
@@ -19,6 +20,7 @@
     error,
     localrepo,
     node as nodemod,
+    store,
     util,
 )
 
@@ -185,6 +187,7 @@
         self._ondisktiprev = None
         self._ondisktipnode = None
         self._unsavedsubranges = {}
+        self._createmode = store._calcmode(self._vfs)
 
     def contains(self, repo, revs):
         con = self._con
@@ -240,12 +243,19 @@
 
     def _db(self):
         try:
-            util.makedirs(self._vfs.dirname(self._path))
+            util.makedirs(self._vfs.dirname(self._path), self._createmode)
         except OSError:
             return None
+        if self._createmode is not None:
+            pre_existed = os.access(self._path, os.R_OK)
         con = sqlite3.connect(encoding.strfromlocal(self._path), timeout=30,
                               isolation_level=r"IMMEDIATE")
         con.text_factory = bytes
+        if self._createmode is not None and not pre_existed:
+            try:
+                os.chmod(self._path, self._createmode & 0o666)
+            except OSError:
+                pass
         return con
 
     @util.propertycache
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-sqlite3-permissions.t	Sun May 03 01:01:19 2020 +0200
@@ -0,0 +1,30 @@
+#require unix-permissions
+
+Test that sqlite3 cache files inherit the permissions of the .hg
+directory like other cache files.
+
+  $ . $TESTDIR/testlib/common.sh
+
+  $ cat << EOF >> $HGRCPATH
+  > [extensions]
+  > evolve =
+  > EOF
+  $ hg init test
+  $ cd test
+  $ chmod 700 .hg
+  $ hg debugupdatecache
+  $ ls -l .hg/cache/evoext_*.sqlite
+  -rw------- * .hg/cache/evoext_obshashrange_v2.sqlite (glob)
+  -rw------- * .hg/cache/evoext_stablerange_v2.sqlite (glob)
+  $ rm -r .hg/cache
+  $ chmod 770 .hg
+  $ hg debugupdatecache
+  $ ls -l .hg/cache/evoext_*.sqlite
+  -rw-rw---- * .hg/cache/evoext_obshashrange_v2.sqlite (glob)
+  -rw-rw---- * .hg/cache/evoext_stablerange_v2.sqlite (glob)
+  $ rm -r .hg/cache
+  $ chmod 774 .hg
+  $ hg debugupdatecache
+  $ ls -l .hg/cache/evoext_*.sqlite
+  -rw-rw-r-- * .hg/cache/evoext_obshashrange_v2.sqlite (glob)
+  -rw-rw-r-- * .hg/cache/evoext_stablerange_v2.sqlite (glob)