By default refuse to create index entries with a path starting with .git/.
authorJelmer Vernooij <jelmer@samba.org>
Thu, 15 Jan 2015 22:30:28 +0000 (23:30 +0100)
committerJelmer Vernooij <jelmer@samba.org>
Thu, 15 Jan 2015 22:30:28 +0000 (23:30 +0100)
NEWS
dulwich/index.py
dulwich/tests/test_index.py

diff --git a/NEWS b/NEWS
index 5520f50e555b673e04c701300a2748148e48e73e..ef2c22f9e90b6467bff798f0e0ab232a1f6e0a57 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,10 @@
 0.9.9  UNRELEASED
 
 0.9.9  UNRELEASED
 
+ BUG FIXES
+
+  * In dulwich.index.build_index_from_tree, by default
+    refuse to create entries that start with .git/.
+
 0.9.8  2014-11-30
 
  BUG FIXES
 0.9.8  2014-11-30
 
  BUG FIXES
index 170ba7756697cca2713695d0d5e91de13305b7de..8b6bbd3466429f919ab33cda2b88c6b6a33b97ab 100644 (file)
@@ -431,8 +431,14 @@ def build_file_from_blob(blob, mode, target_path, honor_filemode=True):
             os.chmod(target_path, mode)
 
 
             os.chmod(target_path, mode)
 
 
+def validate_path_default(path):
+    """Default path validator that just checks for .git/."""
+    return not path.startswith(".git/")
+
+
 def build_index_from_tree(prefix, index_path, object_store, tree_id,
 def build_index_from_tree(prefix, index_path, object_store, tree_id,
-                          honor_filemode=True):
+                          honor_filemode=True,
+                          validate_path=validate_path_default):
     """Generate and materialize index from a tree
 
     :param tree_id: Tree to materialize
     """Generate and materialize index from a tree
 
     :param tree_id: Tree to materialize
@@ -441,6 +447,8 @@ def build_index_from_tree(prefix, index_path, object_store, tree_id,
     :param object_store: Non-empty object store holding tree contents
     :param honor_filemode: An optional flag to honor core.filemode setting in
         config file, default is core.filemode=True, change executable bit
     :param object_store: Non-empty object store holding tree contents
     :param honor_filemode: An optional flag to honor core.filemode setting in
         config file, default is core.filemode=True, change executable bit
+    :param validate_path: Function to validate paths to check out;
+        default just refuses filenames starting with .git/.
 
     :note:: existing index is wiped and contents are not merged
         in a working dir. Suiteable only for fresh clones.
 
     :note:: existing index is wiped and contents are not merged
         in a working dir. Suiteable only for fresh clones.
@@ -449,6 +457,8 @@ def build_index_from_tree(prefix, index_path, object_store, tree_id,
     index = Index(index_path)
 
     for entry in object_store.iter_tree_contents(tree_id):
     index = Index(index_path)
 
     for entry in object_store.iter_tree_contents(tree_id):
+        if not validate_path(entry.path):
+            continue
         full_path = os.path.join(prefix, entry.path)
 
         if not os.path.exists(os.path.dirname(full_path)):
         full_path = os.path.join(prefix, entry.path)
 
         if not os.path.exists(os.path.dirname(full_path)):
index 7077d4557cda519da8c722d3108f0f60c71d4237..10eddc232a6f71b9195aaaf3862934456047c448 100644 (file)
@@ -50,7 +50,6 @@ from dulwich.repo import Repo
 from dulwich.tests import TestCase
 from dulwich.tests.utils import skipIfPY3
 
 from dulwich.tests import TestCase
 from dulwich.tests.utils import skipIfPY3
 
-
 @skipIfPY3
 class IndexTestCase(TestCase):
 
 @skipIfPY3
 class IndexTestCase(TestCase):
 
@@ -281,6 +280,43 @@ class BuildIndexTests(TestCase):
         # Verify no files
         self.assertEqual(['.git'], os.listdir(repo.path))
 
         # Verify no files
         self.assertEqual(['.git'], os.listdir(repo.path))
 
+    def test_git_dir(self):
+        if os.name != 'posix':
+            self.skipTest("test depends on POSIX shell")
+
+        repo_dir = tempfile.mkdtemp()
+        repo = Repo.init(repo_dir)
+        self.addCleanup(shutil.rmtree, repo_dir)
+
+        # Populate repo
+        filea = Blob.from_string('file a')
+        filee = Blob.from_string('d')
+
+        tree = Tree()
+        tree['.git/a'] = (stat.S_IFREG | 0o644, filea.id)
+        tree['c/e'] = (stat.S_IFREG | 0o644, filee.id)
+
+        repo.object_store.add_objects([(o, None)
+            for o in [filea, filee, tree]])
+
+        build_index_from_tree(repo.path, repo.index_path(),
+                repo.object_store, tree.id)
+
+        # Verify index entries
+        index = repo.open_index()
+        self.assertEqual(len(index), 1)
+
+        # filea
+        apath = os.path.join(repo.path, '.git', 'a')
+        self.assertFalse(os.path.exists(apath))
+
+        # filee
+        epath = os.path.join(repo.path, 'c', 'e')
+        self.assertTrue(os.path.exists(epath))
+        self.assertReasonableIndexEntry(index['c/e'],
+            stat.S_IFREG | 0o644, 1, filee.id)
+        self.assertFileContents(epath, 'd')
+
     def test_nonempty(self):
         if os.name != 'posix':
             self.skipTest("test depends on POSIX shell")
     def test_nonempty(self):
         if os.name != 'posix':
             self.skipTest("test depends on POSIX shell")