localrepo: add auditor attribute which knows about subrepos
authorMartin Geisler <mg@lazybytes.net>
Fri, 03 Sep 2010 12:58:51 +0200
changeset 12162 af8c4929931c
parent 12161 dfb11f9922c1
child 12163 505f64bb58af
localrepo: add auditor attribute which knows about subrepos
mercurial/localrepo.py
mercurial/subrepo.py
--- a/mercurial/localrepo.py	Thu Sep 02 23:45:47 2010 +0200
+++ b/mercurial/localrepo.py	Fri Sep 03 12:58:51 2010 +0200
@@ -28,6 +28,7 @@
         self.root = os.path.realpath(util.expandpath(path))
         self.path = os.path.join(self.root, ".hg")
         self.origroot = path
+        self.auditor = util.path_auditor(self.root, self._checknested)
         self.opener = util.opener(self.path)
         self.wopener = util.opener(self.root)
         self.baseui = baseui
@@ -111,6 +112,44 @@
         self._datafilters = {}
         self._transref = self._lockref = self._wlockref = None
 
+    def _checknested(self, path):
+        """Determine if path is a legal nested repository."""
+        if not path.startswith(self.root):
+            return False
+        subpath = path[len(self.root) + 1:]
+
+        # XXX: Checking against the current working copy is wrong in
+        # the sense that it can reject things like
+        #
+        #   $ hg cat -r 10 sub/x.txt
+        #
+        # if sub/ is no longer a subrepository in the working copy
+        # parent revision.
+        #
+        # However, it can of course also allow things that would have
+        # been rejected before, such as the above cat command if sub/
+        # is a subrepository now, but was a normal directory before.
+        # The old path auditor would have rejected by mistake since it
+        # panics when it sees sub/.hg/.
+        #
+        # All in all, checking against the working copy parent
+        # revision seems sensible since we want to prevent access to
+        # nested repositories on the filesystem *now*.
+        ctx = self['.']
+        parts = util.splitpath(subpath)
+        while parts:
+            prefix = os.sep.join(parts)
+            if prefix in ctx.substate:
+                if prefix == subpath:
+                    return True
+                else:
+                    sub = ctx.sub(prefix)
+                    return sub.checknested(subpath[len(prefix) + 1:])
+            else:
+                parts.pop()
+        return False
+
+
     @propertycache
     def changelog(self):
         c = changelog.changelog(self.sopener)
--- a/mercurial/subrepo.py	Thu Sep 02 23:45:47 2010 +0200
+++ b/mercurial/subrepo.py	Fri Sep 03 12:58:51 2010 +0200
@@ -210,6 +210,10 @@
         """
         raise NotImplementedError
 
+    def checknested(path):
+        """check if path is a subrepository within this repository"""
+        return False
+
     def commit(self, text, user, date):
         """commit the current changes to the subrepo with the given
         log message. Use given user and date if possible. Return the
@@ -280,6 +284,9 @@
             return True
         return w.dirty() # working directory changed
 
+    def checknested(self, path):
+        return self._repo._checknested(self._repo.wjoin(path))
+
     def commit(self, text, user, date):
         self._repo.ui.debug("committing subrepo %s\n" % relpath(self))
         n = self._repo.commit(text, user, date)