summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md4
-rw-r--r--include/git2/tree.h6
-rw-r--r--src/notes.c4
-rw-r--r--src/tree.c30
-rw-r--r--src/tree.h1
-rw-r--r--tests/index/tests.c21
-rw-r--r--tests/object/tree/attributes.c30
-rw-r--r--tests/object/tree/duplicateentries.c4
-rw-r--r--tests/object/tree/write.c72
-rw-r--r--tests/repo/iterator.c4
10 files changed, 123 insertions, 53 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cfb4f0430..5dfc27edf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -136,3 +136,7 @@ v0.21 + 1
* git_libgit2_init() and git_libgit2_shutdown() now return the number of
initializations of the library, so consumers may schedule work on the
first initialization.
+
+* git_treebuilder_create now takes a repository so that it can query
+ repository configuration. Subsequently, git_treebuilder_write no
+ longer takes a repository.
diff --git a/include/git2/tree.h b/include/git2/tree.h
index 42b68193e..0f7616210 100644
--- a/include/git2/tree.h
+++ b/include/git2/tree.h
@@ -247,11 +247,12 @@ GIT_EXTERN(int) git_tree_entry_to_object(
* entries and will have to be filled manually.
*
* @param out Pointer where to store the tree builder
+ * @param repo Repository in which to store the object
* @param source Source tree to initialize the builder (optional)
* @return 0 on success; error code otherwise
*/
GIT_EXTERN(int) git_treebuilder_create(
- git_treebuilder **out, const git_tree *source);
+ git_treebuilder **out, git_repository *repo, const git_tree *source);
/**
* Clear all the entires in the builder
@@ -368,12 +369,11 @@ GIT_EXTERN(void) git_treebuilder_filter(
* identifying SHA1 hash will be stored in the `id` pointer.
*
* @param id Pointer to store the OID of the newly written tree
- * @param repo Repository in which to store the object
* @param bld Tree builder to write
* @return 0 or an error code
*/
GIT_EXTERN(int) git_treebuilder_write(
- git_oid *id, git_repository *repo, git_treebuilder *bld);
+ git_oid *id, git_treebuilder *bld);
/** Callback for the tree traversal method */
diff --git a/src/notes.c b/src/notes.c
index 8fdf388ab..a0bc0d355 100644
--- a/src/notes.c
+++ b/src/notes.c
@@ -107,7 +107,7 @@ static int tree_write(
const git_tree_entry *entry;
git_oid tree_oid;
- if ((error = git_treebuilder_create(&tb, source_tree)) < 0)
+ if ((error = git_treebuilder_create(&tb, repo, source_tree)) < 0)
goto cleanup;
if (object_oid) {
@@ -119,7 +119,7 @@ static int tree_write(
goto cleanup;
}
- if ((error = git_treebuilder_write(&tree_oid, repo, tb)) < 0)
+ if ((error = git_treebuilder_write(&tree_oid, tb)) < 0)
goto cleanup;
error = git_tree_lookup(out, repo, &tree_oid);
diff --git a/src/tree.c b/src/tree.c
index 6246ff648..57cc95387 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -50,14 +50,11 @@ GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode)
return GIT_FILEMODE_BLOB;
}
-static int valid_entry_name(const char *filename)
+static int valid_entry_name(git_repository *repo, const char *filename)
{
return *filename != '\0' &&
- strchr(filename, '/') == NULL &&
- (*filename != '.' ||
- (strcmp(filename, ".") != 0 &&
- strcmp(filename, "..") != 0 &&
- strcasecmp(filename, DOT_GIT) != 0));
+ git_path_isvalid(repo, filename,
+ GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT | GIT_PATH_REJECT_SLASH);
}
static int entry_sort_cmp(const void *a, const void *b)
@@ -455,7 +452,7 @@ static int append_entry(
git_tree_entry *entry;
int error = 0;
- if (!valid_entry_name(filename))
+ if (!valid_entry_name(bld->repo, filename))
return tree_error("Failed to insert entry. Invalid name for a tree entry", filename);
entry = alloc_entry(filename);
@@ -493,7 +490,7 @@ static int write_tree(
return (int)find_next_dir(dirname, index, start);
}
- if ((error = git_treebuilder_create(&bld, NULL)) < 0 || bld == NULL)
+ if ((error = git_treebuilder_create(&bld, repo, NULL)) < 0 || bld == NULL)
return -1;
/*
@@ -564,7 +561,7 @@ static int write_tree(
}
}
- if (git_treebuilder_write(oid, repo, bld) < 0)
+ if (git_treebuilder_write(oid, bld) < 0)
goto on_error;
git_treebuilder_free(bld);
@@ -627,16 +624,21 @@ int git_tree__write_index(
return ret;
}
-int git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source)
+int git_treebuilder_create(
+ git_treebuilder **builder_p,
+ git_repository *repo,
+ const git_tree *source)
{
git_treebuilder *bld;
size_t i;
- assert(builder_p);
+ assert(builder_p && repo);
bld = git__calloc(1, sizeof(git_treebuilder));
GITERR_CHECK_ALLOC(bld);
+ bld->repo = repo;
+
if (git_strmap_alloc(&bld->map) < 0) {
git__free(bld);
return -1;
@@ -678,7 +680,7 @@ int git_treebuilder_insert(
if (!valid_filemode(filemode))
return tree_error("Failed to insert entry. Invalid filemode for file", filename);
- if (!valid_entry_name(filename))
+ if (!valid_entry_name(bld->repo, filename))
return tree_error("Failed to insert entry. Invalid name for a tree entry", filename);
pos = git_strmap_lookup_index(bld->map, filename);
@@ -738,7 +740,7 @@ int git_treebuilder_remove(git_treebuilder *bld, const char *filename)
return 0;
}
-int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld)
+int git_treebuilder_write(git_oid *oid, git_treebuilder *bld)
{
int error = 0;
size_t i, entrycount;
@@ -777,7 +779,7 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b
git_vector_free(&entries);
if (!error &&
- !(error = git_repository_odb__weakptr(&odb, repo)))
+ !(error = git_repository_odb__weakptr(&odb, bld->repo)))
error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE);
git_buf_free(&tree);
diff --git a/src/tree.h b/src/tree.h
index 5d27eb7c9..d01b6fd41 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -26,6 +26,7 @@ struct git_tree {
};
struct git_treebuilder {
+ git_repository *repo;
git_strmap *map;
};
diff --git a/tests/index/tests.c b/tests/index/tests.c
index 0464e7337..a6c4b895c 100644
--- a/tests/index/tests.c
+++ b/tests/index/tests.c
@@ -421,6 +421,27 @@ void test_index_tests__write_invalid_filename(void)
cl_fixture_cleanup("invalid");
}
+void test_index_tests__honors_protect_filesystems(void)
+{
+ git_repository *repo;
+
+ p_mkdir("invalid", 0700);
+
+ cl_git_pass(git_repository_init(&repo, "./invalid", 0));
+
+ cl_repo_set_bool(repo, "core.protectHFS", true);
+ cl_repo_set_bool(repo, "core.protectNTFS", true);
+
+ write_invalid_filename(repo, ".git./hello");
+ write_invalid_filename(repo, ".git\xe2\x80\xad/hello");
+ write_invalid_filename(repo, "git~1/hello");
+ write_invalid_filename(repo, ".git\xe2\x81\xaf/hello");
+
+ git_repository_free(repo);
+
+ cl_fixture_cleanup("invalid");
+}
+
void test_index_tests__remove_entry(void)
{
git_repository *repo;
diff --git a/tests/object/tree/attributes.c b/tests/object/tree/attributes.c
index 85216cd1b..14f3f89f9 100644
--- a/tests/object/tree/attributes.c
+++ b/tests/object/tree/attributes.c
@@ -1,9 +1,21 @@
#include "clar_libgit2.h"
#include "tree.h"
+static git_repository *repo;
+
static const char *blob_oid = "3d0970ec547fc41ef8a5882dde99c6adce65b021";
static const char *tree_oid = "1b05fdaa881ee45b48cbaa5e9b037d667a47745e";
+void test_object_tree_attributes__initialize(void)
+{
+ repo = cl_git_sandbox_init("deprecated-mode.git");
+}
+
+void test_object_tree_attributes__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
void test_object_tree_attributes__ensure_correctness_of_attributes_on_insertion(void)
{
git_treebuilder *builder;
@@ -11,7 +23,7 @@ void test_object_tree_attributes__ensure_correctness_of_attributes_on_insertion(
cl_git_pass(git_oid_fromstr(&oid, blob_oid));
- cl_git_pass(git_treebuilder_create(&builder, NULL));
+ cl_git_pass(git_treebuilder_create(&builder, repo, NULL));
cl_git_fail(git_treebuilder_insert(NULL, builder, "one.txt", &oid, (git_filemode_t)0777777));
cl_git_fail(git_treebuilder_insert(NULL, builder, "one.txt", &oid, (git_filemode_t)0100666));
@@ -22,7 +34,6 @@ void test_object_tree_attributes__ensure_correctness_of_attributes_on_insertion(
void test_object_tree_attributes__group_writable_tree_entries_created_with_an_antique_git_version_can_still_be_accessed(void)
{
- git_repository *repo;
git_oid tid;
git_tree *tree;
const git_tree_entry *entry;
@@ -38,7 +49,6 @@ void test_object_tree_attributes__group_writable_tree_entries_created_with_an_an
git_tree_entry_filemode(entry));
git_tree_free(tree);
- git_repository_free(repo);
}
void test_object_tree_attributes__treebuilder_reject_invalid_filemode(void)
@@ -48,7 +58,7 @@ void test_object_tree_attributes__treebuilder_reject_invalid_filemode(void)
const git_tree_entry *entry;
cl_git_pass(git_oid_fromstr(&bid, blob_oid));
- cl_git_pass(git_treebuilder_create(&builder, NULL));
+ cl_git_pass(git_treebuilder_create(&builder, repo, NULL));
cl_git_fail(git_treebuilder_insert(
&entry,
@@ -62,25 +72,22 @@ void test_object_tree_attributes__treebuilder_reject_invalid_filemode(void)
void test_object_tree_attributes__normalize_attributes_when_creating_a_tree_from_an_existing_one(void)
{
- git_repository *repo;
git_treebuilder *builder;
git_oid tid, tid2;
git_tree *tree;
const git_tree_entry *entry;
- repo = cl_git_sandbox_init("deprecated-mode.git");
-
cl_git_pass(git_oid_fromstr(&tid, tree_oid));
cl_git_pass(git_tree_lookup(&tree, repo, &tid));
- cl_git_pass(git_treebuilder_create(&builder, tree));
+ cl_git_pass(git_treebuilder_create(&builder, repo, tree));
entry = git_treebuilder_get(builder, "old_mode.txt");
cl_assert_equal_i(
GIT_FILEMODE_BLOB,
git_tree_entry_filemode(entry));
- cl_git_pass(git_treebuilder_write(&tid2, repo, builder));
+ cl_git_pass(git_treebuilder_write(&tid2, builder));
git_treebuilder_free(builder);
git_tree_free(tree);
@@ -91,18 +98,14 @@ void test_object_tree_attributes__normalize_attributes_when_creating_a_tree_from
git_tree_entry_filemode(entry));
git_tree_free(tree);
- cl_git_sandbox_cleanup();
}
void test_object_tree_attributes__normalize_600(void)
{
git_oid id;
git_tree *tree;
- git_repository *repo;
const git_tree_entry *entry;
- repo = cl_git_sandbox_init("deprecated-mode.git");
-
git_oid_fromstr(&id, "0810fb7818088ff5ac41ee49199b51473b1bd6c7");
cl_git_pass(git_tree_lookup(&tree, repo, &id));
@@ -111,5 +114,4 @@ void test_object_tree_attributes__normalize_600(void)
cl_assert_equal_i(git_tree_entry_filemode_raw(entry), 0100600);
git_tree_free(tree);
- cl_git_sandbox_cleanup();
}
diff --git a/tests/object/tree/duplicateentries.c b/tests/object/tree/duplicateentries.c
index 1b752acbb..11314ec90 100644
--- a/tests/object/tree/duplicateentries.c
+++ b/tests/object/tree/duplicateentries.c
@@ -57,11 +57,11 @@ static void tree_creator(git_oid *out, void (*fn)(git_treebuilder *))
{
git_treebuilder *builder;
- cl_git_pass(git_treebuilder_create(&builder, NULL));
+ cl_git_pass(git_treebuilder_create(&builder, _repo, NULL));
fn(builder);
- cl_git_pass(git_treebuilder_write(out, _repo, builder));
+ cl_git_pass(git_treebuilder_write(out, builder));
git_treebuilder_free(builder);
}
diff --git a/tests/object/tree/write.c b/tests/object/tree/write.c
index ddb62e278..2947ac362 100644
--- a/tests/object/tree/write.c
+++ b/tests/object/tree/write.c
@@ -35,7 +35,7 @@ void test_object_tree_write__from_memory(void)
* on REPOSITORY_FOLDER.
*/
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
- cl_git_pass(git_treebuilder_create(&builder, tree));
+ cl_git_pass(git_treebuilder_create(&builder, g_repo, tree));
cl_git_fail(git_treebuilder_insert(NULL, builder, "",
&bid, GIT_FILEMODE_BLOB));
@@ -53,7 +53,7 @@ void test_object_tree_write__from_memory(void)
cl_git_pass(git_treebuilder_insert(
NULL, builder, "new.txt", &bid, GIT_FILEMODE_BLOB));
- cl_git_pass(git_treebuilder_write(&rid, g_repo, builder));
+ cl_git_pass(git_treebuilder_write(&rid, builder));
cl_assert(git_oid_cmp(&rid, &id2) == 0);
@@ -75,18 +75,18 @@ void test_object_tree_write__subtree(void)
git_oid_fromstr(&bid, blob_oid);
/* create subtree */
- cl_git_pass(git_treebuilder_create(&builder, NULL));
+ cl_git_pass(git_treebuilder_create(&builder, g_repo, NULL));
cl_git_pass(git_treebuilder_insert(
NULL, builder, "new.txt", &bid, GIT_FILEMODE_BLOB)); /* -V536 */
- cl_git_pass(git_treebuilder_write(&subtree_id, g_repo, builder));
+ cl_git_pass(git_treebuilder_write(&subtree_id, builder));
git_treebuilder_free(builder);
/* create parent tree */
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
- cl_git_pass(git_treebuilder_create(&builder, tree));
+ cl_git_pass(git_treebuilder_create(&builder, g_repo, tree));
cl_git_pass(git_treebuilder_insert(
NULL, builder, "new", &subtree_id, GIT_FILEMODE_TREE)); /* -V536 */
- cl_git_pass(git_treebuilder_write(&id_hiearar, g_repo, builder));
+ cl_git_pass(git_treebuilder_write(&id_hiearar, builder));
git_treebuilder_free(builder);
git_tree_free(tree);
@@ -135,14 +135,14 @@ void test_object_tree_write__sorted_subtrees(void)
memset(&blank_oid, 0x0, sizeof(blank_oid));
- cl_git_pass(git_treebuilder_create(&builder, NULL));
+ cl_git_pass(git_treebuilder_create(&builder, g_repo, NULL));
for (i = 0; i < ARRAY_SIZE(entries); ++i) {
cl_git_pass(git_treebuilder_insert(NULL,
builder, entries[i].filename, &blank_oid, entries[i].attr));
}
- cl_git_pass(git_treebuilder_write(&tree_oid, g_repo, builder));
+ cl_git_pass(git_treebuilder_write(&tree_oid, builder));
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_oid));
for (i = 0; i < git_tree_entrycount(tree); i++) {
@@ -192,7 +192,7 @@ void test_object_tree_write__removing_and_re_adding_in_treebuilder(void)
memset(&blank_oid, 0x0, sizeof(blank_oid));
- cl_git_pass(git_treebuilder_create(&builder, NULL));
+ cl_git_pass(git_treebuilder_create(&builder, g_repo, NULL));
cl_assert_equal_i(0, (int)git_treebuilder_entrycount(builder));
@@ -229,7 +229,7 @@ void test_object_tree_write__removing_and_re_adding_in_treebuilder(void)
NULL, builder, "apple_extra", &blank_oid, GIT_FILEMODE_BLOB));
cl_assert_equal_i(7, (int)git_treebuilder_entrycount(builder));
- cl_git_pass(git_treebuilder_write(&tree_oid, g_repo, builder));
+ cl_git_pass(git_treebuilder_write(&tree_oid, builder));
git_treebuilder_free(builder);
@@ -283,7 +283,7 @@ void test_object_tree_write__filtering(void)
memset(&blank_oid, 0x0, sizeof(blank_oid));
- cl_git_pass(git_treebuilder_create(&builder, NULL));
+ cl_git_pass(git_treebuilder_create(&builder, g_repo, NULL));
for (i = 0; _entries[i].filename; ++i)
cl_git_pass(git_treebuilder_insert(NULL,
@@ -310,7 +310,7 @@ void test_object_tree_write__filtering(void)
cl_assert(git_treebuilder_get(builder, "aardvark") == NULL);
cl_assert(git_treebuilder_get(builder, "last") != NULL);
- cl_git_pass(git_treebuilder_write(&tree_oid, g_repo, builder));
+ cl_git_pass(git_treebuilder_write(&tree_oid, builder));
git_treebuilder_free(builder);
@@ -346,13 +346,13 @@ void test_object_tree_write__cruel_paths(void)
git_oid_fromstr(&bid, blob_oid);
/* create tree */
- cl_git_pass(git_treebuilder_create(&builder, NULL));
+ cl_git_pass(git_treebuilder_create(&builder, g_repo, NULL));
for (scan = the_paths; *scan; ++scan) {
cl_git_pass(git_treebuilder_insert(
NULL, builder, *scan, &bid, GIT_FILEMODE_BLOB));
count++;
}
- cl_git_pass(git_treebuilder_write(&id, g_repo, builder));
+ cl_git_pass(git_treebuilder_write(&id, builder));
git_treebuilder_free(builder);
/* check data is correct */
@@ -374,12 +374,12 @@ void test_object_tree_write__cruel_paths(void)
git_tree_free(tree);
/* let's try longer paths */
- cl_git_pass(git_treebuilder_create(&builder, NULL));
+ cl_git_pass(git_treebuilder_create(&builder, g_repo, NULL));
for (scan = the_paths; *scan; ++scan) {
cl_git_pass(git_treebuilder_insert(
NULL, builder, *scan, &id, GIT_FILEMODE_TREE));
}
- cl_git_pass(git_treebuilder_write(&subid, g_repo, builder));
+ cl_git_pass(git_treebuilder_write(&subid, builder));
git_treebuilder_free(builder);
/* check data is correct */
@@ -400,3 +400,43 @@ void test_object_tree_write__cruel_paths(void)
git_tree_free(tree);
}
+
+void test_object_tree_write__protect_filesystems(void)
+{
+ git_treebuilder *builder;
+ git_oid bid;
+
+ /* Ensure that (by default) we can write objects with funny names on
+ * platforms that are not affected.
+ */
+ cl_git_pass(git_treebuilder_create(&builder, g_repo, NULL));
+
+#ifndef GIT_WIN32
+ cl_git_pass(git_treebuilder_insert(NULL, builder, ".git.", &bid, GIT_FILEMODE_BLOB));
+ cl_git_pass(git_treebuilder_insert(NULL, builder, "git~1", &bid, GIT_FILEMODE_BLOB));
+#endif
+
+#ifndef __APPLE__
+ cl_git_pass(git_treebuilder_insert(NULL, builder, ".git\xef\xbb\xbf", &bid, GIT_FILEMODE_BLOB));
+ cl_git_pass(git_treebuilder_insert(NULL, builder, ".git\xe2\x80\xad", &bid, GIT_FILEMODE_BLOB));
+#endif
+
+ git_treebuilder_free(builder);
+
+ /* Now turn on core.protectHFS and core.protectNTFS and validate that these
+ * paths are rejected.
+ */
+
+ cl_repo_set_bool(g_repo, "core.protectHFS", true);
+ cl_repo_set_bool(g_repo, "core.protectNTFS", true);
+
+ cl_git_pass(git_treebuilder_create(&builder, g_repo, NULL));
+
+ cl_git_fail(git_treebuilder_insert(NULL, builder, ".git.", &bid, GIT_FILEMODE_BLOB));
+ cl_git_fail(git_treebuilder_insert(NULL, builder, "git~1", &bid, GIT_FILEMODE_BLOB));
+
+ cl_git_fail(git_treebuilder_insert(NULL, builder, ".git\xef\xbb\xbf", &bid, GIT_FILEMODE_BLOB));
+ cl_git_fail(git_treebuilder_insert(NULL, builder, ".git\xe2\x80\xad", &bid, GIT_FILEMODE_BLOB));
+
+ git_treebuilder_free(builder);
+}
diff --git a/tests/repo/iterator.c b/tests/repo/iterator.c
index fb5561bc2..0e8793d99 100644
--- a/tests/repo/iterator.c
+++ b/tests/repo/iterator.c
@@ -427,7 +427,7 @@ static void build_test_tree(
git_buf name = GIT_BUF_INIT;
va_list arglist;
- cl_git_pass(git_treebuilder_create(&builder, NULL)); /* start builder */
+ cl_git_pass(git_treebuilder_create(&builder, repo, NULL)); /* start builder */
va_start(arglist, fmt);
while (*scan) {
@@ -451,7 +451,7 @@ static void build_test_tree(
}
va_end(arglist);
- cl_git_pass(git_treebuilder_write(out, repo, builder));
+ cl_git_pass(git_treebuilder_write(out, builder));
git_treebuilder_free(builder);
git_buf_free(&name);