context: use a the nofsauditor when matching file in history (issue4749)
authorPierre-Yves David <pierre-yves.david@fb.com>
Thu, 03 Dec 2015 13:23:46 -0800
changeset 27234 15c6eb0a51bd
parent 27233 dfb836a31b61
child 27235 054cd38a2f19
context: use a the nofsauditor when matching file in history (issue4749) Before this change, asking for file from history (eg: 'hg cat -r 42 foo/bar') could fail because of the current content of the working copy (eg: current "foo" being a symlink). As the working copy state have no influence on the content of the history, we can safely skip these checks. The working copy context class have a different 'match' implementation. That implementation still use the repo.auditor will still catch symlink traversal. I've audited all stuff calling "match" and they all go through a ctx in a sensible way. The most unclear case was diff which still seemed okay. You raised my paranoid level today and I double checked through tests. They behave properly. The odds of someone using the wrong (matching with a changectx for operation that will eventually touch the file system) is non-zero because you are never sure of what people will do. But I dunno if we can fight against that. So I would not commit to "never" for "at this level" and "in the future" if someone write especially bad code. However, as a last defense, the vfs itself is running path auditor in all cases outside of .hg/. So I think anything passing the 'matcher' for buggy reason would growl at the vfs layer.
mercurial/context.py
tests/test-audit-path.t
--- a/mercurial/context.py	Thu Dec 03 13:22:36 2015 -0800
+++ b/mercurial/context.py	Thu Dec 03 13:23:46 2015 -0800
@@ -271,7 +271,7 @@
         r = self._repo
         return matchmod.match(r.root, r.getcwd(), pats,
                               include, exclude, default,
-                              auditor=r.auditor, ctx=self,
+                              auditor=r.nofsauditor, ctx=self,
                               listsubrepos=listsubrepos, badfn=badfn)
 
     def diff(self, ctx2=None, match=None, **opts):
--- a/tests/test-audit-path.t	Thu Dec 03 13:22:36 2015 -0800
+++ b/tests/test-audit-path.t	Thu Dec 03 13:23:46 2015 -0800
@@ -27,6 +27,45 @@
   abort: path 'b/b' traverses symbolic link 'b' (glob)
   [255]
 
+  $ hg commit -m 'add symlink b'
+
+
+Test symlink traversing when accessing history:
+-----------------------------------------------
+
+(build a changeset where the path exists as a directory)
+
+  $ hg up 0
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ mkdir b
+  $ echo c > b/a
+  $ hg add b/a
+  $ hg ci -m 'add directory b'
+  created new head
+
+Test that hg cat does not do anything wrong the working copy has 'b' as directory
+
+  $ hg cat b/a
+  c
+  $ hg cat -r "desc(directory)" b/a
+  c
+  $ hg cat -r "desc(symlink)" b/a
+  b/a: no such file in rev bc151a1f53bd
+  [1]
+
+Test that hg cat does not do anything wrong the working copy has 'b' as a symlink (issue4749)
+
+  $ hg up 'desc(symlink)'
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg cat b/a
+  b/a: no such file in rev bc151a1f53bd
+  [1]
+  $ hg cat -r "desc(directory)" b/a
+  c
+  $ hg cat -r "desc(symlink)" b/a
+  b/a: no such file in rev bc151a1f53bd
+  [1]
+
 #endif