Commit b81aa2f1deb98eb7f9e60ac96696e69a9a49d8f8

Ben Straub 2012-11-29T14:06:40

Deploy GIT_CHECKOUT_OPTS_INIT

diff --git a/examples/network/clone.c b/examples/network/clone.c
index a718f30..7596523 100644
--- a/examples/network/clone.c
+++ b/examples/network/clone.c
@@ -51,7 +51,7 @@ int do_clone(git_repository *repo, int argc, char **argv)
 {
 	progress_data pd;
 	git_repository *cloned_repo = NULL;
-	git_checkout_opts checkout_opts;
+	git_checkout_opts checkout_opts = GIT_CHECKOUT_OPTS_INIT;
 	const char *url = argv[1];
 	const char *path = argv[2];
 	int error;
diff --git a/src/checkout.c b/src/checkout.c
index a3166bf..2a7ad70 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -225,10 +225,12 @@ static int retrieve_symlink_caps(git_repository *repo, bool *can_symlink)
 static void normalize_options(
 	git_checkout_opts *normalized, git_checkout_opts *proposed)
 {
+	git_checkout_opts init_opts = GIT_CHECKOUT_OPTS_INIT;
+
 	assert(normalized);
 
 	if (!proposed)
-		memset(normalized, 0, sizeof(git_checkout_opts));
+		memmove(normalized, &init_opts, sizeof(git_checkout_opts));
 	else
 		memmove(normalized, proposed, sizeof(git_checkout_opts));
 
@@ -601,6 +603,19 @@ static int checkout_create_submodules(
 	return 0;
 }
 
+static bool opts_is_valid_version(git_checkout_opts *opts)
+{
+	if (!opts)
+		return true;
+
+	if (opts->version > 0 &&  opts->version <= GIT_CHECKOUT_OPTS_VERSION)
+		return true;
+
+	giterr_set(GITERR_INVALID, "Invalid version %d on git_checkout_opts structure",
+			opts->version);
+	return false;
+}
+
 int git_checkout_index(
 	git_repository *repo,
 	git_index *index,
@@ -624,6 +639,11 @@ int git_checkout_index(
 		GIT_DIFF_INCLUDE_UNMODIFIED | GIT_DIFF_INCLUDE_UNTRACKED |
 		GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_SKIP_BINARY_CHECK;
 
+	if (!opts_is_valid_version(opts)) {
+      error = -1;
+		goto cleanup;
+   }
+
 	if (opts && opts->paths.count > 0)
 		diff_opts.pathspec = opts->paths;
 
diff --git a/src/reset.c b/src/reset.c
index d410a88..17b4b90 100644
--- a/src/reset.c
+++ b/src/reset.c
@@ -69,7 +69,7 @@ int git_reset(
 	git_index *index = NULL;
 	git_tree *tree = NULL;
 	int error = -1;
-	git_checkout_opts opts;
+	git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
 
 	assert(repo && target);
 	assert(reset_type == GIT_RESET_SOFT
@@ -136,7 +136,6 @@ int git_reset(
 		goto cleanup;
 	}
 
-	memset(&opts, 0, sizeof(opts));
 	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
 
 	if (git_checkout_index(repo, NULL, &opts) < 0) {
diff --git a/src/stash.c b/src/stash.c
index 107cbe3..edd8c55 100644
--- a/src/stash.c
+++ b/src/stash.c
@@ -498,9 +498,7 @@ static int reset_index_and_workdir(
 	git_commit *commit,
 	bool remove_untracked)
 {
-	git_checkout_opts opts;
-
-	memset(&opts, 0, sizeof(git_checkout_opts));
+	git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
 
 	opts.checkout_strategy =
 		GIT_CHECKOUT_UPDATE_MODIFIED | GIT_CHECKOUT_UPDATE_UNTRACKED;
diff --git a/tests-clar/checkout/checkout_util.h b/tests-clar/checkout/checkout_util.h
new file mode 100644
index 0000000..d6aa7ed
--- /dev/null
+++ b/tests-clar/checkout/checkout_util.h
@@ -0,0 +1,5 @@
+GIT_INLINE(void) reset_checkout_opts(git_checkout_opts *opts)
+{
+	git_checkout_opts init_opts = GIT_CHECKOUT_OPTS_INIT;
+	memmove(opts, &init_opts, sizeof(git_checkout_opts));
+}
diff --git a/tests-clar/checkout/index.c b/tests-clar/checkout/index.c
index b6d6372..e86dfe9 100644
--- a/tests-clar/checkout/index.c
+++ b/tests-clar/checkout/index.c
@@ -2,6 +2,7 @@
 
 #include "git2/checkout.h"
 #include "repository.h"
+#include "checkout_util.h"
 
 static git_repository *g_repo;
 static git_checkout_opts g_opts;
@@ -25,7 +26,7 @@ void test_checkout_index__initialize(void)
 {
 	git_tree *tree;
 
-	memset(&g_opts, 0, sizeof(g_opts));
+	reset_checkout_opts(&g_opts);
 	g_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
 
 	g_repo = cl_git_sandbox_init("testrepo");
@@ -66,7 +67,7 @@ void test_checkout_index__cannot_checkout_a_bare_repository(void)
 {
 	test_checkout_index__cleanup();
 
-	memset(&g_opts, 0, sizeof(g_opts));
+	reset_checkout_opts(&g_opts);
 	g_repo = cl_git_sandbox_init("testrepo.git");
 
 	cl_git_fail(git_checkout_index(g_repo, NULL, NULL));
@@ -426,3 +427,21 @@ void test_checkout_index__can_overcome_name_clashes(void)
 
 	git_index_free(index);
 }
+
+void test_checkout_index__validates_struct_version(void)
+{
+	const git_error *err;
+
+	g_opts.version = 1024;
+	cl_git_fail(git_checkout_index(g_repo, NULL, &g_opts));
+
+	err = giterr_last();
+	cl_assert_equal_i(err->klass, GITERR_INVALID);
+
+	g_opts.version = 0;
+	giterr_clear();
+	cl_git_fail(git_checkout_index(g_repo, NULL, &g_opts));
+
+	err = giterr_last();
+	cl_assert_equal_i(err->klass, GITERR_INVALID);
+}
diff --git a/tests-clar/checkout/tree.c b/tests-clar/checkout/tree.c
index 534c460..fe5bd4f 100644
--- a/tests-clar/checkout/tree.c
+++ b/tests-clar/checkout/tree.c
@@ -2,6 +2,7 @@
 
 #include "git2/checkout.h"
 #include "repository.h"
+#include "checkout_util.h"
 
 static git_repository *g_repo;
 static git_checkout_opts g_opts;
@@ -11,7 +12,7 @@ void test_checkout_tree__initialize(void)
 {
 	g_repo = cl_git_sandbox_init("testrepo");
 
-	memset(&g_opts, 0, sizeof(g_opts));
+	reset_checkout_opts(&g_opts);
 	g_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
 }
 
diff --git a/tests-clar/checkout/typechange.c b/tests-clar/checkout/typechange.c
index cd34885..98c15bc 100644
--- a/tests-clar/checkout/typechange.c
+++ b/tests-clar/checkout/typechange.c
@@ -38,7 +38,7 @@ void test_checkout_typechange__checkout_typechanges(void)
 {
 	int i;
 	git_object *obj;
-	git_checkout_opts opts = {0};
+	git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
 
 	opts.checkout_strategy = GIT_CHECKOUT_FORCE;