diff -r dfb11f9922c1 -r af8c4929931c mercurial/localrepo.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)