git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere
@ 2020-01-30 23:00 Taylor Blau
  2020-01-30 23:00 ` [PATCH 1/6] t5318: don't pass non-object directory to '--object-dir' Taylor Blau
                   ` (7 more replies)
  0 siblings, 8 replies; 28+ messages in thread
From: Taylor Blau @ 2020-01-30 23:00 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster

Hi,

While working on deploying layered commit-graphs at GitHub, I noticed
that I was able to trigger the mechanism to prevent merging
cross-alternate commit-graph layers in funny ways, like claiming that
"./objects" and "objects" were in different directories.

This resulted in removing all of the places in the commit-graph.c code
that use 'char *object_dir's with 'struct object_directory *'s instead.
This allows us to replace brittle string-based path comparisons with raw
pointer comparisons to check whether two commit-graphs belong to the
same object store or not.

This has a pleasant side effect in PATCH 5/6 of fixing an uninitialized
read as described in [1].

This series became a little bit longer than I was expecting it to be, so
here is the high-level structure:

  - 1/6 fixes a bug in a test that would cause a subsequent failure if
    unaddressed.

  - 2/6 does the first half of the removal by using 'struct
    object_directory *'s within the 'commit_graph' structure.

  - 4/6 does the second half by removing 'char *object_dir' usage in the
    'write_commit_graph_context' structure.

  - 5/6 ties 2/6 and 4/6 together by removing all path normalization
    completely, fixing the uninitialized read bug.

  - And 6/6 cleans up.

We've been running a version of this series based on our fork (which is
in turn based on 2.24) for a few hours without issue.

Thanks in advance for your review.

[1]: https://lore.kernel.org/git/20191027042116.GA5801@sigill.intra.peff.net/

Taylor Blau (6):
  t5318: don't pass non-object directory to '--object-dir'
  commit-graph.h: store object directory in 'struct commit_graph'
  builtin/commit-graph.c: die() with unknown '--object-dir'
  commit-graph.h: store an odb in 'struct write_commit_graph_context'
  commit-graph.c: remove path normalization, comparison
  commit-graph.h: use odb in 'load_commit_graph_one_fd_st'

 Documentation/git-commit-graph.txt |   5 +-
 builtin/commit-graph.c             |  25 ++++--
 builtin/commit.c                   |   3 +-
 builtin/fetch.c                    |   2 +-
 builtin/gc.c                       |   2 +-
 commit-graph.c                     | 135 +++++++++++++++--------------
 commit-graph.h                     |  17 ++--
 t/helper/test-read-graph.c         |   8 +-
 t/t5318-commit-graph.sh            |   4 +-
 9 files changed, 114 insertions(+), 87 deletions(-)

--
2.25.0.dirty

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 1/6] t5318: don't pass non-object directory to '--object-dir'
  2020-01-30 23:00 [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Taylor Blau
@ 2020-01-30 23:00 ` Taylor Blau
  2020-01-30 23:00 ` [PATCH 5/6] commit-graph.c: remove path normalization, comparison Taylor Blau
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 28+ messages in thread
From: Taylor Blau @ 2020-01-30 23:00 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster

In f237c8b6fe (commit-graph: implement git-commit-graph write,
2018-04-02) the test t5318.3 was introduced to ensure that calling 'git
commit-graph write' in a repository with no packfiles does not write any
commit-graph file(s).

To exercise more paths in 'builtin/commit-graph.c', this test passes
'--object-dir' to 'git commit-graph write', but the given argument
refers to the working copy, not the object directory.

Since the commit-graph sub-commands currently swallow these errors, this
does not result in a test failure. But, it is only lucky that the test
ends with no commit-graphs, since there were none to begin with.

In preparation for a future commit where an '--object-dir' argument that
does not match a known object directory will print out a failure, let's
fix the test to still use '--object-dir', but pass the correct location
to the object store instead of '.'.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 t/t5318-commit-graph.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index 3f03de6018..0bf98b56ec 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -19,8 +19,8 @@ test_expect_success 'verify graph with no graph file' '
 
 test_expect_success 'write graph with no packs' '
 	cd "$TRASH_DIRECTORY/full" &&
-	git commit-graph write --object-dir . &&
-	test_path_is_missing info/commit-graph
+	git commit-graph write --object-dir $objdir &&
+	test_path_is_missing $objdir/info/commit-graph
 '
 
 test_expect_success 'exit with correct error on bad input to --stdin-packs' '
-- 
2.25.0.dirty


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 5/6] commit-graph.c: remove path normalization, comparison
  2020-01-30 23:00 [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Taylor Blau
  2020-01-30 23:00 ` [PATCH 1/6] t5318: don't pass non-object directory to '--object-dir' Taylor Blau
@ 2020-01-30 23:00 ` Taylor Blau
  2020-01-30 23:00 ` [PATCH 6/6] commit-graph.h: use odb in 'load_commit_graph_one_fd_st' Taylor Blau
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 28+ messages in thread
From: Taylor Blau @ 2020-01-30 23:00 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster

As of the previous patch, all calls to 'commit-graph.c' functions which
perform path normalization (for e.g., 'get_commit_graph_filename()') are
of the form 'ctx->odb->path', which is always in normalized form.

Now that there are no callers passing non-normalized paths to these
functions, ensure that future callers are bound by the same restrictions
by making these functions take a 'struct object_directory *' instead of
a 'const char *'. To match, replace all calls with arguments of the form
'ctx->odb->path' with 'ctx->odb' To recover the path, functions that
perform path manipulation simply use 'odb->path'.

Further, avoid string comparisons with arguments of the form
'odb->path', and instead prefer raw pointer comparisons, which
accomplish the same effect, but are far less brittle.

This has a pleasant side-effect of making these functions much more
robust to paths that cannot be normalized by 'normalize_path_copy()',
i.e., because they are outside of the current working directory.

For example, prior to this patch, Valgrind reports that the following
uninitialized memory read [1]:

  $ ( cd t && GIT_DIR=../.git valgrind git rev-parse HEAD^ )

because 'normalize_path_copy()' can't normalize '../.git' (since it's
relative to but above of the current working directory) [2].

By using a 'struct object_directory *' directly,
'get_commit_graph_filename()' does not need to normalize, because all
paths are relative to the current working directory since they are
always read from the '->path' of an object directory.

[1]: https://lore.kernel.org/git/20191027042116.GA5801@sigill.intra.peff.net.
[2]: The bug here is that 'get_commit_graph_filename()' returns the
     result of 'normalize_path_copy()' without checking the return
     value.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 builtin/commit-graph.c     | 11 ++++-----
 commit-graph.c             | 47 +++++++++++++++-----------------------
 commit-graph.h             |  2 +-
 t/helper/test-read-graph.c |  6 ++---
 4 files changed, 28 insertions(+), 38 deletions(-)

diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 9b1148a60a..4ab045395e 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -46,6 +46,7 @@ static struct object_directory *find_odb_or_die(struct repository *r,
 static int graph_verify(int argc, const char **argv)
 {
 	struct commit_graph *graph = NULL;
+	struct object_directory *odb = NULL;
 	char *graph_name;
 	int open_ok;
 	int fd;
@@ -76,7 +77,8 @@ static int graph_verify(int argc, const char **argv)
 	if (opts.progress)
 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
 
-	graph_name = get_commit_graph_filename(opts.obj_dir);
+	odb = find_odb_or_die(the_repository, opts.obj_dir);
+	graph_name = get_commit_graph_filename(odb);
 	open_ok = open_commit_graph(graph_name, &fd, &st);
 	if (!open_ok && errno != ENOENT)
 		die_errno(_("Could not open commit-graph '%s'"), graph_name);
@@ -85,11 +87,8 @@ static int graph_verify(int argc, const char **argv)
 
 	if (open_ok)
 		graph = load_commit_graph_one_fd_st(fd, &st);
-	else {
-		struct object_directory *odb;
-		if ((odb = find_odb_or_die(the_repository, opts.obj_dir)))
-			graph = read_commit_graph_one(the_repository, odb);
-	}
+	else
+		graph = read_commit_graph_one(the_repository, odb);
 
 	/* Return failure if open_ok predicted success */
 	if (!graph)
diff --git a/commit-graph.c b/commit-graph.c
index 19889e5fea..09316240f0 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -44,30 +44,21 @@
 /* Remember to update object flag allocation in object.h */
 #define REACHABLE       (1u<<15)
 
-char *get_commit_graph_filename(const char *obj_dir)
+char *get_commit_graph_filename(struct object_directory *odb)
 {
-	char *filename = xstrfmt("%s/info/commit-graph", obj_dir);
-	char *normalized = xmalloc(strlen(filename) + 1);
-	normalize_path_copy(normalized, filename);
-	free(filename);
-	return normalized;
+	return xstrfmt("%s/info/commit-graph", odb->path);
 }
 
-static char *get_split_graph_filename(const char *obj_dir,
+static char *get_split_graph_filename(struct object_directory *odb,
 				      const char *oid_hex)
 {
-	char *filename = xstrfmt("%s/info/commit-graphs/graph-%s.graph",
-				 obj_dir,
-				 oid_hex);
-	char *normalized = xmalloc(strlen(filename) + 1);
-	normalize_path_copy(normalized, filename);
-	free(filename);
-	return normalized;
+	return xstrfmt("%s/info/commit-graphs/graph-%s.graph", odb->path,
+		       oid_hex);
 }
 
-static char *get_chain_filename(const char *obj_dir)
+static char *get_chain_filename(struct object_directory *odb)
 {
-	return xstrfmt("%s/info/commit-graphs/commit-graph-chain", obj_dir);
+	return xstrfmt("%s/info/commit-graphs/commit-graph-chain", odb->path);
 }
 
 static uint8_t oid_version(void)
@@ -350,7 +341,7 @@ static struct commit_graph *load_commit_graph_one(const char *graph_file)
 static struct commit_graph *load_commit_graph_v1(struct repository *r,
 						 struct object_directory *odb)
 {
-	char *graph_name = get_commit_graph_filename(odb->path);
+	char *graph_name = get_commit_graph_filename(odb);
 	struct commit_graph *g = load_commit_graph_one(graph_name);
 	free(graph_name);
 
@@ -401,7 +392,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
 	struct stat st;
 	struct object_id *oids;
 	int i = 0, valid = 1, count;
-	char *chain_name = get_chain_filename(odb->path);
+	char *chain_name = get_chain_filename(odb);
 	FILE *fp;
 	int stat_res;
 
@@ -434,7 +425,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
 
 		valid = 0;
 		for (odb = r->objects->odb; odb; odb = odb->next) {
-			char *graph_name = get_split_graph_filename(odb->path, line.buf);
+			char *graph_name = get_split_graph_filename(odb, line.buf);
 			struct commit_graph *g = load_commit_graph_one(graph_name);
 
 			free(graph_name);
@@ -1395,7 +1386,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 			    ctx->odb->path);
 		ctx->graph_name = strbuf_detach(&tmp_file, NULL);
 	} else {
-		ctx->graph_name = get_commit_graph_filename(ctx->odb->path);
+		ctx->graph_name = get_commit_graph_filename(ctx->odb);
 	}
 
 	if (safe_create_leading_directories(ctx->graph_name)) {
@@ -1406,7 +1397,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 	}
 
 	if (ctx->split) {
-		char *lock_name = get_chain_filename(ctx->odb->path);
+		char *lock_name = get_chain_filename(ctx->odb);
 
 		hold_lock_file_for_update(&lk, lock_name, LOCK_DIE_ON_ERROR);
 
@@ -1494,7 +1485,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 
 	if (ctx->split && ctx->base_graph_name && ctx->num_commit_graphs_after > 1) {
 		char *new_base_hash = xstrdup(oid_to_hex(&ctx->new_base_graph->oid));
-		char *new_base_name = get_split_graph_filename(ctx->new_base_graph->odb->path, new_base_hash);
+		char *new_base_name = get_split_graph_filename(ctx->new_base_graph->odb, new_base_hash);
 
 		free(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 2]);
 		free(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 2]);
@@ -1530,12 +1521,12 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 				}
 			}
 		} else {
-			char *graph_name = get_commit_graph_filename(ctx->odb->path);
+			char *graph_name = get_commit_graph_filename(ctx->odb);
 			unlink(graph_name);
 		}
 
 		ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(oid_to_hex(&file_hash));
-		final_graph_name = get_split_graph_filename(ctx->odb->path,
+		final_graph_name = get_split_graph_filename(ctx->odb,
 					ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
 		ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name;
 
@@ -1577,7 +1568,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 
 	while (g && (g->num_commits <= size_mult * num_commits ||
 		    (max_commits && num_commits > max_commits))) {
-		if (strcmp(g->odb->path, ctx->odb->path))
+		if (g->odb != ctx->odb)
 			break;
 
 		num_commits += g->num_commits;
@@ -1589,10 +1580,10 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 	ctx->new_base_graph = g;
 
 	if (ctx->num_commit_graphs_after == 2) {
-		char *old_graph_name = get_commit_graph_filename(g->odb->path);
+		char *old_graph_name = get_commit_graph_filename(g->odb);
 
 		if (!strcmp(g->filename, old_graph_name) &&
-		    strcmp(g->odb->path, ctx->odb->path)) {
+		    g->odb != ctx->odb) {
 			ctx->num_commit_graphs_after = 1;
 			ctx->new_base_graph = NULL;
 		}
@@ -1743,7 +1734,7 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
 	if (ctx->split_opts && ctx->split_opts->expire_time)
 		expire_time -= ctx->split_opts->expire_time;
 	if (!ctx->split) {
-		char *chain_file_name = get_chain_filename(ctx->odb->path);
+		char *chain_file_name = get_chain_filename(ctx->odb);
 		unlink(chain_file_name);
 		free(chain_file_name);
 		ctx->num_commit_graphs_after = 0;
diff --git a/commit-graph.h b/commit-graph.h
index 39c0c0e51c..97e2bce313 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -12,7 +12,7 @@
 
 struct commit;
 
-char *get_commit_graph_filename(const char *obj_dir);
+char *get_commit_graph_filename(struct object_directory *odb);
 int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
 
 struct object_directory *find_odb(struct repository *r, const char *obj_dir);
diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c
index d2884efe0a..2c2f65f06c 100644
--- a/t/helper/test-read-graph.c
+++ b/t/helper/test-read-graph.c
@@ -11,12 +11,12 @@ int cmd__read_graph(int argc, const char **argv)
 	int open_ok;
 	int fd;
 	struct stat st;
-	const char *object_dir;
+	struct object_directory *odb;
 
 	setup_git_directory();
-	object_dir = get_object_directory();
+	odb = the_repository->objects->odb;
 
-	graph_name = get_commit_graph_filename(object_dir);
+	graph_name = get_commit_graph_filename(odb);
 
 	open_ok = open_commit_graph(graph_name, &fd, &st);
 	if (!open_ok)
-- 
2.25.0.dirty


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 6/6] commit-graph.h: use odb in 'load_commit_graph_one_fd_st'
  2020-01-30 23:00 [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Taylor Blau
  2020-01-30 23:00 ` [PATCH 1/6] t5318: don't pass non-object directory to '--object-dir' Taylor Blau
  2020-01-30 23:00 ` [PATCH 5/6] commit-graph.c: remove path normalization, comparison Taylor Blau
@ 2020-01-30 23:00 ` Taylor Blau
  2020-01-30 23:00 ` [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph' Taylor Blau
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 28+ messages in thread
From: Taylor Blau @ 2020-01-30 23:00 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster

Apply a similar treatment as in the previous patch to pass a 'struct
object_directory *' through the 'load_commit_graph_one_fd_st'
initializer, too.

This prevents a potential bug where a pointer comparison is made to a
NULL 'g->odb', which would cause the commit-graph machinery to think
that a pair of commit-graphs belonged to different alternates when in
fact they do not (i.e., in the case of no '--object-dir').

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 builtin/commit-graph.c     |  2 +-
 commit-graph.c             | 21 ++++++++++-----------
 commit-graph.h             |  3 ++-
 t/helper/test-read-graph.c |  2 +-
 4 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 4ab045395e..de321c71ad 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -86,7 +86,7 @@ static int graph_verify(int argc, const char **argv)
 	FREE_AND_NULL(graph_name);
 
 	if (open_ok)
-		graph = load_commit_graph_one_fd_st(fd, &st);
+		graph = load_commit_graph_one_fd_st(fd, &st, odb);
 	else
 		graph = read_commit_graph_one(the_repository, odb);
 
diff --git a/commit-graph.c b/commit-graph.c
index 09316240f0..6d34829f57 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -128,7 +128,8 @@ int open_commit_graph(const char *graph_file, int *fd, struct stat *st)
 	return 1;
 }
 
-struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st)
+struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st,
+						 struct object_directory *odb)
 {
 	void *graph_map;
 	size_t graph_size;
@@ -144,7 +145,9 @@ struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st)
 	graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
 	ret = parse_commit_graph(graph_map, fd, graph_size);
 
-	if (!ret) {
+	if (ret)
+		ret->odb = odb;
+	else {
 		munmap(graph_map, graph_size);
 		close(fd);
 	}
@@ -319,7 +322,8 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
 	return graph;
 }
 
-static struct commit_graph *load_commit_graph_one(const char *graph_file)
+static struct commit_graph *load_commit_graph_one(const char *graph_file,
+						  struct object_directory *odb)
 {
 
 	struct stat st;
@@ -330,7 +334,7 @@ static struct commit_graph *load_commit_graph_one(const char *graph_file)
 	if (!open_ok)
 		return NULL;
 
-	g = load_commit_graph_one_fd_st(fd, &st);
+	g = load_commit_graph_one_fd_st(fd, &st, odb);
 
 	if (g)
 		g->filename = xstrdup(graph_file);
@@ -342,12 +346,9 @@ static struct commit_graph *load_commit_graph_v1(struct repository *r,
 						 struct object_directory *odb)
 {
 	char *graph_name = get_commit_graph_filename(odb);
-	struct commit_graph *g = load_commit_graph_one(graph_name);
+	struct commit_graph *g = load_commit_graph_one(graph_name, odb);
 	free(graph_name);
 
-	if (g)
-		g->odb = odb;
-
 	return g;
 }
 
@@ -426,13 +427,11 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
 		valid = 0;
 		for (odb = r->objects->odb; odb; odb = odb->next) {
 			char *graph_name = get_split_graph_filename(odb, line.buf);
-			struct commit_graph *g = load_commit_graph_one(graph_name);
+			struct commit_graph *g = load_commit_graph_one(graph_name, odb);
 
 			free(graph_name);
 
 			if (g) {
-				g->odb = odb;
-
 				if (add_graph_to_chain(g, graph_chain, oids, i)) {
 					graph_chain = g;
 					valid = 1;
diff --git a/commit-graph.h b/commit-graph.h
index 97e2bce313..7d9fc9c16a 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -63,7 +63,8 @@ struct commit_graph {
 	const unsigned char *chunk_base_graphs;
 };
 
-struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st);
+struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st,
+						 struct object_directory *odb);
 struct commit_graph *read_commit_graph_one(struct repository *r,
 					   struct object_directory *odb);
 struct commit_graph *parse_commit_graph(void *graph_map, int fd,
diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c
index 2c2f65f06c..f8a461767c 100644
--- a/t/helper/test-read-graph.c
+++ b/t/helper/test-read-graph.c
@@ -22,7 +22,7 @@ int cmd__read_graph(int argc, const char **argv)
 	if (!open_ok)
 		die_errno(_("Could not open commit-graph '%s'"), graph_name);
 
-	graph = load_commit_graph_one_fd_st(fd, &st);
+	graph = load_commit_graph_one_fd_st(fd, &st, odb);
 	if (!graph)
 		return 1;
 
-- 
2.25.0.dirty

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph'
  2020-01-30 23:00 [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Taylor Blau
                   ` (2 preceding siblings ...)
  2020-01-30 23:00 ` [PATCH 6/6] commit-graph.h: use odb in 'load_commit_graph_one_fd_st' Taylor Blau
@ 2020-01-30 23:00 ` Taylor Blau
  2020-01-31  6:52   ` Martin Ågren
  2020-01-30 23:00 ` [PATCH 4/6] commit-graph.h: store an odb in 'struct write_commit_graph_context' Taylor Blau
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 28+ messages in thread
From: Taylor Blau @ 2020-01-30 23:00 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster

There are lots of places in 'commit-graph.h' where a function either has
(or almost has) a full 'struct object_directory *', accesses '->path',
and then throws away the rest of the struct.

This can cause headaches when comparing the locations of object
directories across alternates (e.g., in the case of deciding if two
commit-graph layers can be merged). These paths are normalized with
'normalize_path_copy()' which mitigates some comparison issues, but not
all [1].

Instead of getting rid of the 'struct object_directory *', store that
insead of a 'char *odb' in 'struct commit_graph'. Once the 'struct
write_commit_graph_context' has an object_directory pointer, too, this
will allow calling code to replace these error-prone path comparisons
with raw pointer comparisons, thereby circumventing any
normalization-related errors. This will be introduced in a subsequent
patch.

[1]: In my testing, for example, I can get one side of the commit-graph
code to fill object_dir with "./objects" and the other with just
"objects".

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 builtin/commit-graph.c | 13 +++++++---
 builtin/commit.c       |  1 +
 commit-graph.c         | 59 ++++++++++++++++++++++++++++++------------
 commit-graph.h         |  8 ++++--
 4 files changed, 58 insertions(+), 23 deletions(-)

diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index e0c6fc4bbf..3edac318e8 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -76,8 +76,11 @@ static int graph_verify(int argc, const char **argv)
 
 	if (open_ok)
 		graph = load_commit_graph_one_fd_st(fd, &st);
-	 else
-		graph = read_commit_graph_one(the_repository, opts.obj_dir);
+	else {
+		struct object_directory *odb;
+		if ((odb = find_odb(the_repository, opts.obj_dir)))
+			graph = read_commit_graph_one(the_repository, odb);
+	}
 
 	/* Return failure if open_ok predicted success */
 	if (!graph)
@@ -97,6 +100,7 @@ static int graph_write(int argc, const char **argv)
 	struct string_list lines;
 	int result = 0;
 	enum commit_graph_write_flags flags = 0;
+	struct object_directory *odb = NULL;
 
 	static struct option builtin_commit_graph_write_options[] = {
 		OPT_STRING(0, "object-dir", &opts.obj_dir,
@@ -145,9 +149,10 @@ static int graph_write(int argc, const char **argv)
 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
 
 	read_replace_refs = 0;
+	odb = find_odb(the_repository, opts.obj_dir);
 
 	if (opts.reachable) {
-		if (write_commit_graph_reachable(opts.obj_dir, flags, &split_opts))
+		if (write_commit_graph_reachable(odb->path, flags, &split_opts))
 			return 1;
 		return 0;
 	}
@@ -169,7 +174,7 @@ static int graph_write(int argc, const char **argv)
 		UNLEAK(buf);
 	}
 
-	if (write_commit_graph(opts.obj_dir,
+	if (write_commit_graph(odb->path,
 			       pack_indexes,
 			       commit_hex,
 			       flags,
diff --git a/builtin/commit.c b/builtin/commit.c
index aa1332308a..bd071169d7 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -36,6 +36,7 @@
 #include "help.h"
 #include "commit-reach.h"
 #include "commit-graph.h"
+#include "object-store.h"
 
 static const char * const builtin_commit_usage[] = {
 	N_("git commit [<options>] [--] <pathspec>..."),
diff --git a/commit-graph.c b/commit-graph.c
index b205e65ed1..2c06876b26 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -75,6 +75,26 @@ static uint8_t oid_version(void)
 	return 1;
 }
 
+struct object_directory *find_odb(struct repository *r, const char *obj_dir)
+{
+	struct object_directory *odb;
+	char *obj_dir_real = real_pathdup(obj_dir, 1);
+	int cmp = -1;
+
+	prepare_alt_odb(r);
+	for (odb = r->objects->odb; odb; odb = odb->next) {
+		cmp = strcmp(obj_dir_real, real_path(odb->path));
+		if (!cmp)
+			break;
+	}
+
+	free(obj_dir_real);
+
+	if (cmp)
+		odb = NULL;
+	return odb;
+}
+
 static struct commit_graph *alloc_commit_graph(void)
 {
 	struct commit_graph *g = xcalloc(1, sizeof(*g));
@@ -327,14 +347,15 @@ static struct commit_graph *load_commit_graph_one(const char *graph_file)
 	return g;
 }
 
-static struct commit_graph *load_commit_graph_v1(struct repository *r, const char *obj_dir)
+static struct commit_graph *load_commit_graph_v1(struct repository *r,
+						 struct object_directory *odb)
 {
-	char *graph_name = get_commit_graph_filename(obj_dir);
+	char *graph_name = get_commit_graph_filename(odb->path);
 	struct commit_graph *g = load_commit_graph_one(graph_name);
 	free(graph_name);
 
 	if (g)
-		g->obj_dir = obj_dir;
+		g->odb = odb;
 
 	return g;
 }
@@ -372,14 +393,15 @@ static int add_graph_to_chain(struct commit_graph *g,
 	return 1;
 }
 
-static struct commit_graph *load_commit_graph_chain(struct repository *r, const char *obj_dir)
+static struct commit_graph *load_commit_graph_chain(struct repository *r,
+						    struct object_directory *odb)
 {
 	struct commit_graph *graph_chain = NULL;
 	struct strbuf line = STRBUF_INIT;
 	struct stat st;
 	struct object_id *oids;
 	int i = 0, valid = 1, count;
-	char *chain_name = get_chain_filename(obj_dir);
+	char *chain_name = get_chain_filename(odb->path);
 	FILE *fp;
 	int stat_res;
 
@@ -418,7 +440,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r, const
 			free(graph_name);
 
 			if (g) {
-				g->obj_dir = odb->path;
+				g->odb = odb;
 
 				if (add_graph_to_chain(g, graph_chain, oids, i)) {
 					graph_chain = g;
@@ -442,23 +464,25 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r, const
 	return graph_chain;
 }
 
-struct commit_graph *read_commit_graph_one(struct repository *r, const char *obj_dir)
+struct commit_graph *read_commit_graph_one(struct repository *r,
+					   struct object_directory *odb)
 {
-	struct commit_graph *g = load_commit_graph_v1(r, obj_dir);
+	struct commit_graph *g = load_commit_graph_v1(r, odb);
 
 	if (!g)
-		g = load_commit_graph_chain(r, obj_dir);
+		g = load_commit_graph_chain(r, odb);
 
 	return g;
 }
 
-static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
+static void prepare_commit_graph_one(struct repository *r,
+				     struct object_directory *odb)
 {
 
 	if (r->objects->commit_graph)
 		return;
 
-	r->objects->commit_graph = read_commit_graph_one(r, obj_dir);
+	r->objects->commit_graph = read_commit_graph_one(r, odb);
 }
 
 /*
@@ -505,7 +529,7 @@ static int prepare_commit_graph(struct repository *r)
 	for (odb = r->objects->odb;
 	     !r->objects->commit_graph && odb;
 	     odb = odb->next)
-		prepare_commit_graph_one(r, odb->path);
+		prepare_commit_graph_one(r, odb);
 	return !!r->objects->commit_graph;
 }
 
@@ -1470,7 +1494,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 
 	if (ctx->split && ctx->base_graph_name && ctx->num_commit_graphs_after > 1) {
 		char *new_base_hash = xstrdup(oid_to_hex(&ctx->new_base_graph->oid));
-		char *new_base_name = get_split_graph_filename(ctx->new_base_graph->obj_dir, new_base_hash);
+		char *new_base_name = get_split_graph_filename(ctx->new_base_graph->odb->path, new_base_hash);
 
 		free(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 2]);
 		free(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 2]);
@@ -1553,7 +1577,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 
 	while (g && (g->num_commits <= size_mult * num_commits ||
 		    (max_commits && num_commits > max_commits))) {
-		if (strcmp(g->obj_dir, ctx->obj_dir))
+		if (strcmp(g->odb->path, ctx->obj_dir))
 			break;
 
 		num_commits += g->num_commits;
@@ -1565,10 +1589,10 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 	ctx->new_base_graph = g;
 
 	if (ctx->num_commit_graphs_after == 2) {
-		char *old_graph_name = get_commit_graph_filename(g->obj_dir);
+		char *old_graph_name = get_commit_graph_filename(g->odb->path);
 
 		if (!strcmp(g->filename, old_graph_name) &&
-		    strcmp(g->obj_dir, ctx->obj_dir)) {
+		    strcmp(g->odb->path, ctx->obj_dir)) {
 			ctx->num_commit_graphs_after = 1;
 			ctx->new_base_graph = NULL;
 		}
@@ -1824,7 +1848,8 @@ int write_commit_graph(const char *obj_dir,
 		ctx->oids.alloc = split_opts->max_commits;
 
 	if (ctx->append) {
-		prepare_commit_graph_one(ctx->r, ctx->obj_dir);
+		struct object_directory *odb = find_odb(ctx->r, ctx->obj_dir);
+		prepare_commit_graph_one(ctx->r, odb);
 		if (ctx->r->objects->commit_graph)
 			ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
 	}
diff --git a/commit-graph.h b/commit-graph.h
index 7f5c933fa2..9700a6c7c2 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -5,6 +5,7 @@
 #include "repository.h"
 #include "string-list.h"
 #include "cache.h"
+#include "object-store.h"
 
 #define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
 #define GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD "GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD"
@@ -14,6 +15,8 @@ struct commit;
 char *get_commit_graph_filename(const char *obj_dir);
 int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
 
+struct object_directory *find_odb(struct repository *r, const char *obj_dir);
+
 /*
  * Given a commit struct, try to fill the commit struct info, including:
  *  1. tree object
@@ -48,7 +51,7 @@ struct commit_graph {
 	uint32_t num_commits;
 	struct object_id oid;
 	char *filename;
-	const char *obj_dir;
+	struct object_directory *odb;
 
 	uint32_t num_commits_in_base;
 	struct commit_graph *base_graph;
@@ -61,7 +64,8 @@ struct commit_graph {
 };
 
 struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st);
-struct commit_graph *read_commit_graph_one(struct repository *r, const char *obj_dir);
+struct commit_graph *read_commit_graph_one(struct repository *r,
+					   struct object_directory *odb);
 struct commit_graph *parse_commit_graph(void *graph_map, int fd,
 					size_t graph_size);
 
-- 
2.25.0.dirty


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 4/6] commit-graph.h: store an odb in 'struct write_commit_graph_context'
  2020-01-30 23:00 [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Taylor Blau
                   ` (3 preceding siblings ...)
  2020-01-30 23:00 ` [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph' Taylor Blau
@ 2020-01-30 23:00 ` Taylor Blau
  2020-01-30 23:00 ` [PATCH 3/6] builtin/commit-graph.c: die() with unknown '--object-dir' Taylor Blau
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 28+ messages in thread
From: Taylor Blau @ 2020-01-30 23:00 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster

In a previous patch, the 'char *object_dir' in 'struct commit_graph' was
replaced with a 'struct object_directory'. This patch applies the same
treatement to 'struct write_commit_graph_context', which is an
intermediate step towards getting rid of all path normalization in
'commit-graph.c'.

Instead of taking a 'char *object_dir', functions that construct a
'struct write_commit_graph_context' now take a 'struct object_directory
*'. Any code that needs an object directory path use '->path' instead.

This ensures that all calls to functions that perform path normalization
are given arguments which do not themselves require normalization. This
prepares those functions to drop their normalization entirely, which
will occur in the subsequent patch.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 builtin/commit-graph.c |  4 ++--
 builtin/commit.c       |  2 +-
 builtin/fetch.c        |  2 +-
 builtin/gc.c           |  2 +-
 commit-graph.c         | 42 ++++++++++++++++--------------------------
 commit-graph.h         |  4 ++--
 6 files changed, 23 insertions(+), 33 deletions(-)

diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 93ff90d73b..9b1148a60a 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -161,7 +161,7 @@ static int graph_write(int argc, const char **argv)
 	odb = find_odb_or_die(the_repository, opts.obj_dir);
 
 	if (opts.reachable) {
-		if (write_commit_graph_reachable(odb->path, flags, &split_opts))
+		if (write_commit_graph_reachable(odb, flags, &split_opts))
 			return 1;
 		return 0;
 	}
@@ -183,7 +183,7 @@ static int graph_write(int argc, const char **argv)
 		UNLEAK(buf);
 	}
 
-	if (write_commit_graph(odb->path,
+	if (write_commit_graph(odb,
 			       pack_indexes,
 			       commit_hex,
 			       flags,
diff --git a/builtin/commit.c b/builtin/commit.c
index bd071169d7..9df3733e96 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1689,7 +1689,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		      "not exceeded, and then \"git restore --staged :/\" to recover."));
 
 	if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
-	    write_commit_graph_reachable(get_object_directory(), 0, NULL))
+	    write_commit_graph_reachable(the_repository->objects->odb, 0, NULL))
 		return 1;
 
 	repo_rerere(the_repository, 0);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index b4c6d921d0..1ce16c96e9 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1870,7 +1870,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 		if (progress)
 			commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;
 
-		write_commit_graph_reachable(get_object_directory(),
+		write_commit_graph_reachable(the_repository->objects->odb,
 					     commit_graph_flags,
 					     NULL);
 	}
diff --git a/builtin/gc.c b/builtin/gc.c
index 3f76bf4aa7..8e0b9cf41b 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -686,7 +686,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 
 	prepare_repo_settings(the_repository);
 	if (the_repository->settings.gc_write_commit_graph == 1)
-		write_commit_graph_reachable(get_object_directory(),
+		write_commit_graph_reachable(the_repository->objects->odb,
 					     !quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
 					     NULL);
 
diff --git a/commit-graph.c b/commit-graph.c
index 2c06876b26..19889e5fea 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -796,7 +796,7 @@ struct packed_oid_list {
 
 struct write_commit_graph_context {
 	struct repository *r;
-	char *obj_dir;
+	struct object_directory *odb;
 	char *graph_name;
 	struct packed_oid_list oids;
 	struct packed_commit_list commits;
@@ -1173,7 +1173,7 @@ static int add_ref_to_list(const char *refname,
 	return 0;
 }
 
-int write_commit_graph_reachable(const char *obj_dir,
+int write_commit_graph_reachable(struct object_directory *odb,
 				 enum commit_graph_write_flags flags,
 				 const struct split_commit_graph_opts *split_opts)
 {
@@ -1181,7 +1181,7 @@ int write_commit_graph_reachable(const char *obj_dir,
 	int result;
 
 	for_each_ref(add_ref_to_list, &list);
-	result = write_commit_graph(obj_dir, NULL, &list,
+	result = write_commit_graph(odb, NULL, &list,
 				    flags, split_opts);
 
 	string_list_clear(&list, 0);
@@ -1196,7 +1196,7 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,
 	struct strbuf packname = STRBUF_INIT;
 	int dirlen;
 
-	strbuf_addf(&packname, "%s/pack/", ctx->obj_dir);
+	strbuf_addf(&packname, "%s/pack/", ctx->odb->path);
 	dirlen = packname.len;
 	if (ctx->report_progress) {
 		strbuf_addf(&progress_title,
@@ -1392,10 +1392,10 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 
 		strbuf_addf(&tmp_file,
 			    "%s/info/commit-graphs/tmp_graph_XXXXXX",
-			    ctx->obj_dir);
+			    ctx->odb->path);
 		ctx->graph_name = strbuf_detach(&tmp_file, NULL);
 	} else {
-		ctx->graph_name = get_commit_graph_filename(ctx->obj_dir);
+		ctx->graph_name = get_commit_graph_filename(ctx->odb->path);
 	}
 
 	if (safe_create_leading_directories(ctx->graph_name)) {
@@ -1406,7 +1406,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 	}
 
 	if (ctx->split) {
-		char *lock_name = get_chain_filename(ctx->obj_dir);
+		char *lock_name = get_chain_filename(ctx->odb->path);
 
 		hold_lock_file_for_update(&lk, lock_name, LOCK_DIE_ON_ERROR);
 
@@ -1530,12 +1530,12 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 				}
 			}
 		} else {
-			char *graph_name = get_commit_graph_filename(ctx->obj_dir);
+			char *graph_name = get_commit_graph_filename(ctx->odb->path);
 			unlink(graph_name);
 		}
 
 		ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(oid_to_hex(&file_hash));
-		final_graph_name = get_split_graph_filename(ctx->obj_dir,
+		final_graph_name = get_split_graph_filename(ctx->odb->path,
 					ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
 		ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name;
 
@@ -1577,7 +1577,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 
 	while (g && (g->num_commits <= size_mult * num_commits ||
 		    (max_commits && num_commits > max_commits))) {
-		if (strcmp(g->odb->path, ctx->obj_dir))
+		if (strcmp(g->odb->path, ctx->odb->path))
 			break;
 
 		num_commits += g->num_commits;
@@ -1592,7 +1592,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 		char *old_graph_name = get_commit_graph_filename(g->odb->path);
 
 		if (!strcmp(g->filename, old_graph_name) &&
-		    strcmp(g->odb->path, ctx->obj_dir)) {
+		    strcmp(g->odb->path, ctx->odb->path)) {
 			ctx->num_commit_graphs_after = 1;
 			ctx->new_base_graph = NULL;
 		}
@@ -1743,13 +1743,13 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
 	if (ctx->split_opts && ctx->split_opts->expire_time)
 		expire_time -= ctx->split_opts->expire_time;
 	if (!ctx->split) {
-		char *chain_file_name = get_chain_filename(ctx->obj_dir);
+		char *chain_file_name = get_chain_filename(ctx->odb->path);
 		unlink(chain_file_name);
 		free(chain_file_name);
 		ctx->num_commit_graphs_after = 0;
 	}
 
-	strbuf_addstr(&path, ctx->obj_dir);
+	strbuf_addstr(&path, ctx->odb->path);
 	strbuf_addstr(&path, "/info/commit-graphs");
 	dir = opendir(path.buf);
 
@@ -1788,7 +1788,7 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
 	strbuf_release(&path);
 }
 
-int write_commit_graph(const char *obj_dir,
+int write_commit_graph(struct object_directory *odb,
 		       struct string_list *pack_indexes,
 		       struct string_list *commit_hex,
 		       enum commit_graph_write_flags flags,
@@ -1796,7 +1796,6 @@ int write_commit_graph(const char *obj_dir,
 {
 	struct write_commit_graph_context *ctx;
 	uint32_t i, count_distinct = 0;
-	size_t len;
 	int res = 0;
 
 	if (!commit_graph_compatible(the_repository))
@@ -1804,14 +1803,7 @@ int write_commit_graph(const char *obj_dir,
 
 	ctx = xcalloc(1, sizeof(struct write_commit_graph_context));
 	ctx->r = the_repository;
-
-	/* normalize object dir with no trailing slash */
-	ctx->obj_dir = xmallocz(strlen(obj_dir) + 1);
-	normalize_path_copy(ctx->obj_dir, obj_dir);
-	len = strlen(ctx->obj_dir);
-	if (len && ctx->obj_dir[len - 1] == '/')
-		ctx->obj_dir[len - 1] = 0;
-
+	ctx->odb = odb;
 	ctx->append = flags & COMMIT_GRAPH_WRITE_APPEND ? 1 : 0;
 	ctx->report_progress = flags & COMMIT_GRAPH_WRITE_PROGRESS ? 1 : 0;
 	ctx->split = flags & COMMIT_GRAPH_WRITE_SPLIT ? 1 : 0;
@@ -1848,8 +1840,7 @@ int write_commit_graph(const char *obj_dir,
 		ctx->oids.alloc = split_opts->max_commits;
 
 	if (ctx->append) {
-		struct object_directory *odb = find_odb(ctx->r, ctx->obj_dir);
-		prepare_commit_graph_one(ctx->r, odb);
+		prepare_commit_graph_one(ctx->r, ctx->odb);
 		if (ctx->r->objects->commit_graph)
 			ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
 	}
@@ -1923,7 +1914,6 @@ int write_commit_graph(const char *obj_dir,
 	free(ctx->graph_name);
 	free(ctx->commits.list);
 	free(ctx->oids.list);
-	free(ctx->obj_dir);
 
 	if (ctx->commit_graph_filenames_after) {
 		for (i = 0; i < ctx->num_commit_graphs_after; i++) {
diff --git a/commit-graph.h b/commit-graph.h
index 9700a6c7c2..39c0c0e51c 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -95,10 +95,10 @@ struct split_commit_graph_opts {
  * is not compatible with the commit-graph feature, then the
  * methods will return 0 without writing a commit-graph.
  */
-int write_commit_graph_reachable(const char *obj_dir,
+int write_commit_graph_reachable(struct object_directory *odb,
 				 enum commit_graph_write_flags flags,
 				 const struct split_commit_graph_opts *split_opts);
-int write_commit_graph(const char *obj_dir,
+int write_commit_graph(struct object_directory *odb,
 		       struct string_list *pack_indexes,
 		       struct string_list *commit_hex,
 		       enum commit_graph_write_flags flags,
-- 
2.25.0.dirty


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 3/6] builtin/commit-graph.c: die() with unknown '--object-dir'
  2020-01-30 23:00 [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Taylor Blau
                   ` (4 preceding siblings ...)
  2020-01-30 23:00 ` [PATCH 4/6] commit-graph.h: store an odb in 'struct write_commit_graph_context' Taylor Blau
@ 2020-01-30 23:00 ` Taylor Blau
  2020-01-31 10:30 ` [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Jeff King
  2020-02-03 21:17 ` [PATCH v2 0/5] " Taylor Blau
  7 siblings, 0 replies; 28+ messages in thread
From: Taylor Blau @ 2020-01-30 23:00 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster

The commit-graph sub-commands 'write', 'verify' both take an
'--object-dir' argument, which is used to specify the location of an
object directory containing commit-graphs.

However, there was no verification that the '--object-dir' argument
was an object directory. In the case of an '--object-dir' argument that
either (1) doesn't exist, or (2) isn't an object directory, 'git
commit-graph ...' would exit silently with status zero.

This can clearly lead to unintended behavior, such as verifying
commit-graphs that aren't in a repository's own object store (or one of
its alternates), or causing a typo to mask a legitimate commit-graph
verification failure.

To remedy this, let's wrap 'find_odb()' with 'find_odb_or_die()' and
cause the above such errors to produce an error and non-zero exit code.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 Documentation/git-commit-graph.txt |  5 ++++-
 builtin/commit-graph.c             | 13 +++++++++++--
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index bcd85c1976..28d1fee505 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -26,7 +26,10 @@ OPTIONS
 	file. This parameter exists to specify the location of an alternate
 	that only has the objects directory, not a full `.git` directory. The
 	commit-graph file is expected to be in the `<dir>/info` directory and
-	the packfiles are expected to be in `<dir>/pack`.
+	the packfiles are expected to be in `<dir>/pack`. If the directory
+	could not be made into an absolute path, or does not match any known
+	object directory, `git commit-graph ...` will exit with non-zero
+	status.
 
 --[no-]progress::
 	Turn progress on/off explicitly. If neither is specified, progress is
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 3edac318e8..93ff90d73b 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -34,6 +34,15 @@ static struct opts_commit_graph {
 	int progress;
 } opts;
 
+static struct object_directory *find_odb_or_die(struct repository *r,
+						const char *obj_dir)
+{
+	struct object_directory *odb = find_odb(r, obj_dir);
+	if (!odb)
+		die(_("could not find object directory matching %s"), obj_dir);
+	return odb;
+}
+
 static int graph_verify(int argc, const char **argv)
 {
 	struct commit_graph *graph = NULL;
@@ -78,7 +87,7 @@ static int graph_verify(int argc, const char **argv)
 		graph = load_commit_graph_one_fd_st(fd, &st);
 	else {
 		struct object_directory *odb;
-		if ((odb = find_odb(the_repository, opts.obj_dir)))
+		if ((odb = find_odb_or_die(the_repository, opts.obj_dir)))
 			graph = read_commit_graph_one(the_repository, odb);
 	}
 
@@ -149,7 +158,7 @@ static int graph_write(int argc, const char **argv)
 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
 
 	read_replace_refs = 0;
-	odb = find_odb(the_repository, opts.obj_dir);
+	odb = find_odb_or_die(the_repository, opts.obj_dir);
 
 	if (opts.reachable) {
 		if (write_commit_graph_reachable(odb->path, flags, &split_opts))
-- 
2.25.0.dirty


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph'
  2020-01-30 23:00 ` [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph' Taylor Blau
@ 2020-01-31  6:52   ` Martin Ågren
  2020-01-31 10:20     ` Jeff King
                       ` (2 more replies)
  0 siblings, 3 replies; 28+ messages in thread
From: Martin Ågren @ 2020-01-31  6:52 UTC (permalink / raw)
  To: Taylor Blau; +Cc: Git Mailing List, Jeff King, Derrick Stolee, Junio C Hamano

On Fri, 31 Jan 2020 at 00:03, Taylor Blau <me@ttaylorr.com> wrote:
> Instead of getting rid of the 'struct object_directory *', store that
> insead of a 'char *odb' in 'struct commit_graph'. Once the 'struct

s/insead/instead/

>         if (open_ok)
>                 graph = load_commit_graph_one_fd_st(fd, &st);
> -        else
> -               graph = read_commit_graph_one(the_repository, opts.obj_dir);
> +       else {
> +               struct object_directory *odb;
> +               if ((odb = find_odb(the_repository, opts.obj_dir)))
> +                       graph = read_commit_graph_one(the_repository, odb);
> +       }

I'm a tiny bit allergic to this assignment-within-if. It's wrapped by
another pair of parentheses, which both compilers and humans know to
interpret as "trust me, this is not a mistake", but I still find this
easier to read:

  odb = find_odb(...);
  if (odb)
          ....

> --- a/builtin/commit.c
> +++ b/builtin/commit.c

> +#include "object-store.h"

This is the only change in this file, which looks a bit odd. I haven't
actually applied your patches, to be honest, but is this inclusion
really needed?

> --- a/commit-graph.c
> +++ b/commit-graph.c

> +struct object_directory *find_odb(struct repository *r, const char *obj_dir)

This doesn't look commit-graph related -- could/should it go somewhere
else?

> +{
> +       struct object_directory *odb;
> +       char *obj_dir_real = real_pathdup(obj_dir, 1);
> +       int cmp = -1;
> +
> +       prepare_alt_odb(r);
> +       for (odb = r->objects->odb; odb; odb = odb->next) {
> +               cmp = strcmp(obj_dir_real, real_path(odb->path));
> +               if (!cmp)
> +                       break;
> +       }

At this point, either odb is NULL or cmp is zero. Those are the only two
ways out of the loop.

> +       free(obj_dir_real);
> +
> +       if (cmp)
> +               odb = NULL;

Meaning that this doesn't do much? If the most recent comparison failed,
it's because we didn't find anything, so odb will be NULL.

> +       return odb;
> +}

I think you could drop `cmp` and that final check, and write the loop
body as "if (!strcmp(...)) break". You could also have an empty loop
body, but I wouldn't go there -- I'd find that less readable. (Maybe
that's just me.)

Martin

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph'
  2020-01-31  6:52   ` Martin Ågren
@ 2020-01-31 10:20     ` Jeff King
  2020-01-31 19:19       ` Martin Ågren
  2020-02-03  4:36       ` Taylor Blau
  2020-01-31 20:49     ` Junio C Hamano
  2020-02-03  3:58     ` Taylor Blau
  2 siblings, 2 replies; 28+ messages in thread
From: Jeff King @ 2020-01-31 10:20 UTC (permalink / raw)
  To: Martin Ågren
  Cc: Taylor Blau, Git Mailing List, Derrick Stolee, Junio C Hamano

On Fri, Jan 31, 2020 at 07:52:02AM +0100, Martin Ågren wrote:

> > --- a/commit-graph.c
> > +++ b/commit-graph.c
> 
> > +struct object_directory *find_odb(struct repository *r, const char *obj_dir)
> 
> This doesn't look commit-graph related -- could/should it go somewhere
> else?

I think the right place is actually as a static inside
builtin/commit-graph.c, as this is really about handling its weird
--object-dir options.

But it can't go there in this patch, because there's a caller in
commit-graph.c. In patch 4, we convert write_commit_graph() to take an
odb, too, and that call goes away. At that point, we could move it into
the builtin as a static.

Ideally we could flip the order of this patch and patch 4, but that
doesn't work either: by switching to an odb we lose our path
normalization, but if the other side hasn't switched either, then we
can't just compare odb pointers. It would be a temporary regression.

So there's a circular dependency between the two patches. I think we
ought to do done of:

  - move find_odb() to a static as a cleanup on top

  - squash those two patches together into a single

  - swap the patch order, but have write_commit_graph_ctx store both the
    "odb" _and_ the normalized copy of the path we do now. That leaves
    it correct, and then it can be cleaned up in favor of an odb pointer
    comparison in patch 5, along with the rest of the normalized bits.

I'm OK with any of those. The second two have the added bonus that we
could introduce the die() behavior into find_odb() immediately, and
explain it (there's another temporary weirdness in this patch where
specifying an --object-dir outside of the repository becomes a silent
noop, and then the next patch turns it into an error, but that could all
be done in a single step when we introduce find_odb()).

> I think you could drop `cmp` and that final check, and write the loop
> body as "if (!strcmp(...)) break". You could also have an empty loop
> body, but I wouldn't go there -- I'd find that less readable. (Maybe
> that's just me.)

Yeah, I believe you are correct (and this is a nice simplification worth
doing).

-Peff

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere
  2020-01-30 23:00 [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Taylor Blau
                   ` (5 preceding siblings ...)
  2020-01-30 23:00 ` [PATCH 3/6] builtin/commit-graph.c: die() with unknown '--object-dir' Taylor Blau
@ 2020-01-31 10:30 ` Jeff King
  2020-01-31 13:22   ` Derrick Stolee
  2020-02-03 21:17 ` [PATCH v2 0/5] " Taylor Blau
  7 siblings, 1 reply; 28+ messages in thread
From: Jeff King @ 2020-01-31 10:30 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, dstolee, gitster

On Thu, Jan 30, 2020 at 03:00:40PM -0800, Taylor Blau wrote:

> This series became a little bit longer than I was expecting it to be, so
> here is the high-level structure:
> 
>   - 1/6 fixes a bug in a test that would cause a subsequent failure if
>     unaddressed.
> 
>   - 2/6 does the first half of the removal by using 'struct
>     object_directory *'s within the 'commit_graph' structure.
> 
>   - 4/6 does the second half by removing 'char *object_dir' usage in the
>     'write_commit_graph_context' structure.
> 
>   - 5/6 ties 2/6 and 4/6 together by removing all path normalization
>     completely, fixing the uninitialized read bug.
> 
>   - And 6/6 cleans up.

With the exception of the patch-ordering discussion in the sub-thread
with Martin, this looks good to me.

Patch 3 is a change in user-visible behavior, as it restricts how
--object-dir can be used (it must be the main object-dir or an alternate
within the repository). I don't _think_ anybody would care, as the
semantics of those options seemed kind of ill-defined to me in the first
place. But it's worth calling out as a potential risk. I suppose the
alternative is to make a one-off fake "struct object_directory" within
the process that isn't connected to the repository. But if nobody cares,
I'd just as soon avoid that.

One other funny thing with this series: the Date headers of your patches
seem out of order. They ordering in your cover letter here is fine and
presumably reflects the commit topology:

> Taylor Blau (6):
>   t5318: don't pass non-object directory to '--object-dir'
>   commit-graph.h: store object directory in 'struct commit_graph'
>   builtin/commit-graph.c: die() with unknown '--object-dir'
>   commit-graph.h: store an odb in 'struct write_commit_graph_context'
>   commit-graph.c: remove path normalization, comparison
>   commit-graph.h: use odb in 'load_commit_graph_one_fd_st'

but the Date headers in order of 1-6 are:

  Date:   Thu, 30 Jan 2020 15:00:43 -0800
  Date:   Thu, 30 Jan 2020 15:00:50 -0800
  Date:   Thu, 30 Jan 2020 15:00:54 -0800
  Date:   Thu, 30 Jan 2020 15:00:52 -0800
  Date:   Thu, 30 Jan 2020 15:00:45 -0800
  Date:   Thu, 30 Jan 2020 15:00:47 -0800

It's like your sending script rewrites the Date header and puts a
2-second bump between each one (which is good, and what git-send-email
does), but got fed the patches in the wrong order (perhaps their
_original_ date order, if there was clean-up rebasing).

-Peff

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere
  2020-01-31 10:30 ` [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Jeff King
@ 2020-01-31 13:22   ` Derrick Stolee
  2020-02-03  4:38     ` Taylor Blau
  0 siblings, 1 reply; 28+ messages in thread
From: Derrick Stolee @ 2020-01-31 13:22 UTC (permalink / raw)
  To: Jeff King, Taylor Blau; +Cc: git, dstolee, gitster

On 1/31/2020 5:30 AM, Jeff King wrote:
> On Thu, Jan 30, 2020 at 03:00:40PM -0800, Taylor Blau wrote:
> 
>> This series became a little bit longer than I was expecting it to be, so
>> here is the high-level structure:
>>
>>   - 1/6 fixes a bug in a test that would cause a subsequent failure if
>>     unaddressed.
>>
>>   - 2/6 does the first half of the removal by using 'struct
>>     object_directory *'s within the 'commit_graph' structure.
>>
>>   - 4/6 does the second half by removing 'char *object_dir' usage in the
>>     'write_commit_graph_context' structure.
>>
>>   - 5/6 ties 2/6 and 4/6 together by removing all path normalization
>>     completely, fixing the uninitialized read bug.
>>
>>   - And 6/6 cleans up.
> 
> With the exception of the patch-ordering discussion in the sub-thread
> with Martin, this looks good to me.

I agree. Martin's comment is a good one. I can't find anything else
to improve the series.

> Patch 3 is a change in user-visible behavior, as it restricts how
> --object-dir can be used (it must be the main object-dir or an alternate
> within the repository). I don't _think_ anybody would care, as the
> semantics of those options seemed kind of ill-defined to me in the first
> place. But it's worth calling out as a potential risk. I suppose the
> alternative is to make a one-off fake "struct object_directory" within
> the process that isn't connected to the repository. But if nobody cares,
> I'd just as soon avoid that.

I think that this change of behavior is fine, especially because if
someone writes a commit-graph to an --object-dir that is not an
alternate, then that repo will not discover the new commit-graph
anyway.

I do like that you state a possible work-around in case someone shows
up with a legitimate use case for a non-alternate object-dir.

Thanks,
-Stolee


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph'
  2020-01-31 10:20     ` Jeff King
@ 2020-01-31 19:19       ` Martin Ågren
  2020-02-03  4:36       ` Taylor Blau
  1 sibling, 0 replies; 28+ messages in thread
From: Martin Ågren @ 2020-01-31 19:19 UTC (permalink / raw)
  To: Jeff King; +Cc: Taylor Blau, Git Mailing List, Derrick Stolee, Junio C Hamano

On Fri, 31 Jan 2020 at 11:20, Jeff King <peff@peff.net> wrote:
>
> On Fri, Jan 31, 2020 at 07:52:02AM +0100, Martin Ågren wrote:
>
> > > --- a/commit-graph.c
> > > +++ b/commit-graph.c
> >
> > > +struct object_directory *find_odb(struct repository *r, const char *obj_dir)
> >
> > This doesn't look commit-graph related -- could/should it go somewhere
> > else?
>
> I think the right place is actually as a static inside
> builtin/commit-graph.c, as this is really about handling its weird
> --object-dir options.
>
> But it can't go there in this patch, because there's a caller in
> commit-graph.c. In patch 4, we convert write_commit_graph() to take an
> odb, too, and that call goes away. At that point, we could move it into
> the builtin as a static.

Thanks for explaining the issue.

> Ideally we could flip the order of this patch and patch 4, but that
> doesn't work either: by switching to an odb we lose our path
> normalization, but if the other side hasn't switched either, then we
> can't just compare odb pointers. It would be a temporary regression.
>
> So there's a circular dependency between the two patches. I think we
> ought to do done of:
>
>   - move find_odb() to a static as a cleanup on top
>
>   - squash those two patches together into a single
>
>   - swap the patch order, but have write_commit_graph_ctx store both the
>     "odb" _and_ the normalized copy of the path we do now. That leaves
>     it correct, and then it can be cleaned up in favor of an odb pointer
>     comparison in patch 5, along with the rest of the normalized bits.
>
> I'm OK with any of those. The second two have the added bonus that we
> could introduce the die() behavior into find_odb() immediately, and
> explain it (there's another temporary weirdness in this patch where
> specifying an --object-dir outside of the repository becomes a silent
> noop, and then the next patch turns it into an error, but that could all
> be done in a single step when we introduce find_odb()).

... and these ways of addressing it.

Martin

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph'
  2020-01-31  6:52   ` Martin Ågren
  2020-01-31 10:20     ` Jeff King
@ 2020-01-31 20:49     ` Junio C Hamano
  2020-02-03  3:58     ` Taylor Blau
  2 siblings, 0 replies; 28+ messages in thread
From: Junio C Hamano @ 2020-01-31 20:49 UTC (permalink / raw)
  To: Martin Ågren
  Cc: Taylor Blau, Git Mailing List, Jeff King, Derrick Stolee

Martin Ågren <martin.agren@gmail.com> writes:

>> +               struct object_directory *odb;
>> +               if ((odb = find_odb(the_repository, opts.obj_dir)))
>> +                       graph = read_commit_graph_one(the_repository, odb);
>> +       }
>
> I'm a tiny bit allergic to this assignment-within-if. It's wrapped by
> another pair of parentheses, which both compilers and humans know to
> interpret as "trust me, this is not a mistake", but I still find this
> easier to read:
>
>   odb = find_odb(...);
>   if (odb)
>           ....

Yup.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph'
  2020-01-31  6:52   ` Martin Ågren
  2020-01-31 10:20     ` Jeff King
  2020-01-31 20:49     ` Junio C Hamano
@ 2020-02-03  3:58     ` Taylor Blau
  2 siblings, 0 replies; 28+ messages in thread
From: Taylor Blau @ 2020-02-03  3:58 UTC (permalink / raw)
  To: Martin Ågren
  Cc: Taylor Blau, Git Mailing List, Jeff King, Derrick Stolee,
	Junio C Hamano

Hi Martin,

Thanks for your review! Your comments were all quite helpful, and I
applied all of your suggested changes.

On Fri, Jan 31, 2020 at 07:52:02AM +0100, Martin Ågren wrote:
> On Fri, 31 Jan 2020 at 00:03, Taylor Blau <me@ttaylorr.com> wrote:
> > Instead of getting rid of the 'struct object_directory *', store that
> > insead of a 'char *odb' in 'struct commit_graph'. Once the 'struct
>
> s/insead/instead/

Typo. Thanks for noticing. I fixed this in my local copy of this branch.

> >         if (open_ok)
> >                 graph = load_commit_graph_one_fd_st(fd, &st);
> > -        else
> > -               graph = read_commit_graph_one(the_repository, opts.obj_dir);
> > +       else {
> > +               struct object_directory *odb;
> > +               if ((odb = find_odb(the_repository, opts.obj_dir)))
> > +                       graph = read_commit_graph_one(the_repository, odb);
> > +       }
>
> I'm a tiny bit allergic to this assignment-within-if. It's wrapped by
> another pair of parentheses, which both compilers and humans know to
> interpret as "trust me, this is not a mistake", but I still find this
> easier to read:
>
>   odb = find_odb(...);
>   if (odb)
>           ....

To be honest, I'm not such a fan of this style myself, but it seemed odd
to me to write:

  struct object_directory *odb;
  odb = ...;
  if (odb) {
  }

when we were really only trying to call 'find_odb()' and do something
with its result, but only if it was non-NULL. I counted 152 of these
assign-if's laying around with:

  $ git grep 'if ((.* =[^=]' | wc -l

but it seems like they are in poor style (as evidenced by your and
Junio's response later in the thread). So, I removed this and instead
promoted 'odb' to a local variable at the function level, since we
do that promotion anyway in a couple of patches later. This reduces the
churn, and avoids either an assign-if, or a define/assign/check.

> > --- a/builtin/commit.c
> > +++ b/builtin/commit.c
>
> > +#include "object-store.h"

No; this is a stray left over from some development on this branch. I'll
remove it.

> This is the only change in this file, which looks a bit odd. I haven't
> actually applied your patches, to be honest, but is this inclusion
> really needed?
>
> > --- a/commit-graph.c
> > +++ b/commit-graph.c
>
> > +struct object_directory *find_odb(struct repository *r, const char *obj_dir)
>
> This doesn't look commit-graph related -- could/should it go somewhere
> else?

I'll respond in more complete detail further down in the thread, but the
short answer is "yes, this should go in builtin/commit-graph.c".

> > +{
> > +       struct object_directory *odb;
> > +       char *obj_dir_real = real_pathdup(obj_dir, 1);
> > +       int cmp = -1;
> > +
> > +       prepare_alt_odb(r);
> > +       for (odb = r->objects->odb; odb; odb = odb->next) {
> > +               cmp = strcmp(obj_dir_real, real_path(odb->path));
> > +               if (!cmp)
> > +                       break;
> > +       }
>
> At this point, either odb is NULL or cmp is zero. Those are the only two
> ways out of the loop.
>
> > +       free(obj_dir_real);
> > +
> > +       if (cmp)
> > +               odb = NULL;
>
> Meaning that this doesn't do much? If the most recent comparison failed,
> it's because we didn't find anything, so odb will be NULL.
>
> > +       return odb;
> > +}
>
> I think you could drop `cmp` and that final check, and write the loop
> body as "if (!strcmp(...)) break". You could also have an empty loop
> body, but I wouldn't go there -- I'd find that less readable. (Maybe
> that's just me.)

Thanks, I changed this to remove the 'cmp' check outside of the loop,
which I agree is unnecessary.

> Martin

Thanks,
Taylor

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph'
  2020-01-31 10:20     ` Jeff King
  2020-01-31 19:19       ` Martin Ågren
@ 2020-02-03  4:36       ` Taylor Blau
  2020-02-03  8:36         ` Jeff King
  1 sibling, 1 reply; 28+ messages in thread
From: Taylor Blau @ 2020-02-03  4:36 UTC (permalink / raw)
  To: Jeff King
  Cc: Martin Ågren, Taylor Blau, Git Mailing List, Derrick Stolee,
	Junio C Hamano

On Fri, Jan 31, 2020 at 05:20:49AM -0500, Jeff King wrote:
> On Fri, Jan 31, 2020 at 07:52:02AM +0100, Martin Ågren wrote:
>
> > > --- a/commit-graph.c
> > > +++ b/commit-graph.c
> >
> > > +struct object_directory *find_odb(struct repository *r, const char *obj_dir)
> >
> > This doesn't look commit-graph related -- could/should it go somewhere
> > else?
>
> I think the right place is actually as a static inside
> builtin/commit-graph.c, as this is really about handling its weird
> --object-dir options.
>
> But it can't go there in this patch, because there's a caller in
> commit-graph.c. In patch 4, we convert write_commit_graph() to take an
> odb, too, and that call goes away. At that point, we could move it into
> the builtin as a static.
>
> Ideally we could flip the order of this patch and patch 4, but that
> doesn't work either: by switching to an odb we lose our path
> normalization, but if the other side hasn't switched either, then we
> can't just compare odb pointers. It would be a temporary regression.
>
> So there's a circular dependency between the two patches. I think we
> ought to do done of:
>
>   - move find_odb() to a static as a cleanup on top
>
>   - squash those two patches together into a single
>
>   - swap the patch order, but have write_commit_graph_ctx store both the
>     "odb" _and_ the normalized copy of the path we do now. That leaves
>     it correct, and then it can be cleaned up in favor of an odb pointer
>     comparison in patch 5, along with the rest of the normalized bits.

Thanks for describing the problem, and for laying out a few options!

I went with this option, which was to swap patches 2/6 and 4/6, and then
squashing 3/6 into what _was_ 4/6 (but is now 2/5).

That all said, I am not sure that I follow the explanation that we need
to have 'write_commit_graph_ctx' store the normalized object_dir, since
we can use 'odb->path' for this instead. I double checked, and we
already do the same loose normalization in
'sha1-file.c:link_alt_odb_entry()', where we remove trailing slashes.

This isn't the exact same normalization strictly speaking. It differs
only in that we remove more than one trailing slash if it exists, but
this seems acceptable for the 2 patches that this behavior changes lives
on for.

I double checked that the 'odb->path' is normalized relative to the $PWD,
in which case I think that we can rely on it as a stand-in for
'object_dir', and don't have to store both.

> I'm OK with any of those. The second two have the added bonus that we
> could introduce the die() behavior into find_odb() immediately, and
> explain it (there's another temporary weirdness in this patch where
> specifying an --object-dir outside of the repository becomes a silent
> noop, and then the next patch turns it into an error, but that could all
> be done in a single step when we introduce find_odb()).
>
> > I think you could drop `cmp` and that final check, and write the loop
> > body as "if (!strcmp(...)) break". You could also have an empty loop
> > body, but I wouldn't go there -- I'd find that less readable. (Maybe
> > that's just me.)
>
> Yeah, I believe you are correct (and this is a nice simplification worth
> doing).
>
> -Peff

Thanks,
Taylor

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere
  2020-01-31 13:22   ` Derrick Stolee
@ 2020-02-03  4:38     ` Taylor Blau
  0 siblings, 0 replies; 28+ messages in thread
From: Taylor Blau @ 2020-02-03  4:38 UTC (permalink / raw)
  To: Derrick Stolee; +Cc: Jeff King, Taylor Blau, git, dstolee, gitster

On Fri, Jan 31, 2020 at 08:22:42AM -0500, Derrick Stolee wrote:
> On 1/31/2020 5:30 AM, Jeff King wrote:
> > On Thu, Jan 30, 2020 at 03:00:40PM -0800, Taylor Blau wrote:
> >
> >> This series became a little bit longer than I was expecting it to be, so
> >> here is the high-level structure:
> >>
> >>   - 1/6 fixes a bug in a test that would cause a subsequent failure if
> >>     unaddressed.
> >>
> >>   - 2/6 does the first half of the removal by using 'struct
> >>     object_directory *'s within the 'commit_graph' structure.
> >>
> >>   - 4/6 does the second half by removing 'char *object_dir' usage in the
> >>     'write_commit_graph_context' structure.
> >>
> >>   - 5/6 ties 2/6 and 4/6 together by removing all path normalization
> >>     completely, fixing the uninitialized read bug.
> >>
> >>   - And 6/6 cleans up.
> >
> > With the exception of the patch-ordering discussion in the sub-thread
> > with Martin, this looks good to me.
>
> I agree. Martin's comment is a good one. I can't find anything else
> to improve the series.

Thanks for your review!

> > Patch 3 is a change in user-visible behavior, as it restricts how
> > --object-dir can be used (it must be the main object-dir or an alternate
> > within the repository). I don't _think_ anybody would care, as the
> > semantics of those options seemed kind of ill-defined to me in the first
> > place. But it's worth calling out as a potential risk. I suppose the
> > alternative is to make a one-off fake "struct object_directory" within
> > the process that isn't connected to the repository. But if nobody cares,
> > I'd just as soon avoid that.
>
> I think that this change of behavior is fine, especially because if
> someone writes a commit-graph to an --object-dir that is not an
> alternate, then that repo will not discover the new commit-graph
> anyway.

And thanks for the ack. I would be somewhat surprised if someone were
really relying on this behavior in practice.

> I do like that you state a possible work-around in case someone shows
> up with a legitimate use case for a non-alternate object-dir.
>
> Thanks,
> -Stolee

Thanks,
Taylor

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph'
  2020-02-03  4:36       ` Taylor Blau
@ 2020-02-03  8:36         ` Jeff King
  0 siblings, 0 replies; 28+ messages in thread
From: Jeff King @ 2020-02-03  8:36 UTC (permalink / raw)
  To: Taylor Blau
  Cc: Martin Ågren, Git Mailing List, Derrick Stolee,
	Junio C Hamano

On Sun, Feb 02, 2020 at 08:36:46PM -0800, Taylor Blau wrote:

> That all said, I am not sure that I follow the explanation that we need
> to have 'write_commit_graph_ctx' store the normalized object_dir, since
> we can use 'odb->path' for this instead. I double checked, and we
> already do the same loose normalization in
> 'sha1-file.c:link_alt_odb_entry()', where we remove trailing slashes.

I was assuming that the normalization in write_commit_graph_ctx was
necessary (and I think there are some tests around this), but I admit I
didn't actually try it. If it's not failing tests, I'm OK with comparing
the non-normalized paths as an intermediate step, since we end up
comparing pointers after the final patches.

-Peff

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v2 0/5] commit-graph: use 'struct object_directory *' everywhere
  2020-01-30 23:00 [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Taylor Blau
                   ` (6 preceding siblings ...)
  2020-01-31 10:30 ` [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Jeff King
@ 2020-02-03 21:17 ` Taylor Blau
  2020-02-03 21:17   ` [PATCH v2 1/5] t5318: don't pass non-object directory to '--object-dir' Taylor Blau
                     ` (5 more replies)
  7 siblings, 6 replies; 28+ messages in thread
From: Taylor Blau @ 2020-02-03 21:17 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, martin.agren

Hi,

Here is a re-roll of the series in this thread to replace string-based
path comparison in 'commit-graph.c' code with raw pointer comparison of
'struct object_directory *'s.

The only thing that has changed substantially since v1 is that I swapped
the order of patches 2/6 and 4/6. What was patch 3/6 got folded into
what is now patch 2/5. This resolves an inconvenience where we had to
define a helper function in 'commit-graph.c', when it really belonged in
'builtin/commit-graph.c'.

I took a few other suggestions from Martin in what is now patch 4/5, and
noticed a few other small things along the way. A range-diff since v1 is
included below.

Thanks as always,
Taylor

Taylor Blau (5):
  t5318: don't pass non-object directory to '--object-dir'
  commit-graph.h: store an odb in 'struct write_commit_graph_context'
  commit-graph.h: store object directory in 'struct commit_graph'
  commit-graph.c: remove path normalization, comparison
  commit-graph.h: use odb in 'load_commit_graph_one_fd_st'

 Documentation/git-commit-graph.txt |   5 +-
 builtin/commit-graph.c             |  34 +++++++--
 builtin/commit.c                   |   2 +-
 builtin/fetch.c                    |   2 +-
 builtin/gc.c                       |   2 +-
 commit-graph.c                     | 115 +++++++++++++----------------
 commit-graph.h                     |  15 ++--
 t/helper/test-read-graph.c         |   8 +-
 t/t5318-commit-graph.sh            |   4 +-
 9 files changed, 100 insertions(+), 87 deletions(-)

Range-diff against v1:
1:  09ba72c85a = 1:  84a8709ad1 t5318: don't pass non-object directory to '--object-dir'
4:  9784a5db3c ! 2:  d9819cfb33 commit-graph.h: store an odb in 'struct write_commit_graph_context'
    @@ Metadata
      ## Commit message ##
         commit-graph.h: store an odb in 'struct write_commit_graph_context'

    -    In a previous patch, the 'char *object_dir' in 'struct commit_graph' was
    -    replaced with a 'struct object_directory'. This patch applies the same
    -    treatement to 'struct write_commit_graph_context', which is an
    -    intermediate step towards getting rid of all path normalization in
    -    'commit-graph.c'.
    -
    -    Instead of taking a 'char *object_dir', functions that construct a
    -    'struct write_commit_graph_context' now take a 'struct object_directory
    -    *'. Any code that needs an object directory path use '->path' instead.
    -
    -    This ensures that all calls to functions that perform path normalization
    -    are given arguments which do not themselves require normalization. This
    -    prepares those functions to drop their normalization entirely, which
    -    will occur in the subsequent patch.
    +    There are lots of places in 'commit-graph.h' where a function either has
    +    (or almost has) a full 'struct object_directory *', accesses '->path',
    +    and then throws away the rest of the struct.
    +
    +    This can cause headaches when comparing the locations of object
    +    directories across alternates (e.g., in the case of deciding if two
    +    commit-graph layers can be merged). These paths are normalized with
    +    'normalize_path_copy()' which mitigates some comparison issues, but not
    +    all [1].
    +
    +    Replace usage of 'char *object_dir' with 'odb->path' by storing a
    +    'struct object_directory *' in the 'write_commit_graph_context'
    +    structure. This is an intermediate step towards getting rid of all path
    +    normalization in 'commit-graph.c'.
    +
    +    Resolving a user-provided '--object-dir' argument now requires that we
    +    compare it to the known alternates for equality.  Prior to this patch,
    +    an unknown '--object-dir' argument would silently exit with status zero.
    +
    +    This can clearly lead to unintended behavior, such as verifying
    +    commit-graphs that aren't in a repository's own object store (or one of
    +    its alternates), or causing a typo to mask a legitimate commit-graph
    +    verification failure. Make this error non-silent by 'die()'-ing when the
    +    given '--object-dir' does not match any known alternate object store.
    +
    +    [1]: In my testing, for example, I can get one side of the commit-graph
    +    code to fill object_dir with "./objects" and the other with just
    +    "objects".

         Signed-off-by: Taylor Blau <me@ttaylorr.com>

    + ## Documentation/git-commit-graph.txt ##
    +@@ Documentation/git-commit-graph.txt: OPTIONS
    + 	file. This parameter exists to specify the location of an alternate
    + 	that only has the objects directory, not a full `.git` directory. The
    + 	commit-graph file is expected to be in the `<dir>/info` directory and
    +-	the packfiles are expected to be in `<dir>/pack`.
    ++	the packfiles are expected to be in `<dir>/pack`. If the directory
    ++	could not be made into an absolute path, or does not match any known
    ++	object directory, `git commit-graph ...` will exit with non-zero
    ++	status.
    +
    + --[no-]progress::
    + 	Turn progress on/off explicitly. If neither is specified, progress is
    +
      ## builtin/commit-graph.c ##
    +@@ builtin/commit-graph.c: static struct opts_commit_graph {
    + 	int progress;
    + } opts;
    +
    ++struct object_directory *find_odb(struct repository *r, const char *obj_dir)
    ++{
    ++	struct object_directory *odb;
    ++	char *obj_dir_real = real_pathdup(obj_dir, 1);
    ++
    ++	prepare_alt_odb(r);
    ++	for (odb = r->objects->odb; odb; odb = odb->next) {
    ++		if (!strcmp(obj_dir_real, real_path(odb->path)))
    ++			break;
    ++	}
    ++
    ++	free(obj_dir_real);
    ++
    ++	if (!odb)
    ++		die(_("could not find object directory matching %s"), obj_dir);
    ++	return odb;
    ++}
    ++
    + static int graph_verify(int argc, const char **argv)
    + {
    + 	struct commit_graph *graph = NULL;
    ++	struct object_directory *odb = NULL;
    + 	char *graph_name;
    + 	int open_ok;
    + 	int fd;
    +@@ builtin/commit-graph.c: static int graph_verify(int argc, const char **argv)
    + 	if (opts.progress)
    + 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
    +
    +-	graph_name = get_commit_graph_filename(opts.obj_dir);
    ++	odb = find_odb(the_repository, opts.obj_dir);
    ++	graph_name = get_commit_graph_filename(odb->path);
    + 	open_ok = open_commit_graph(graph_name, &fd, &st);
    + 	if (!open_ok && errno != ENOENT)
    + 		die_errno(_("Could not open commit-graph '%s'"), graph_name);
    +@@ builtin/commit-graph.c: static int graph_verify(int argc, const char **argv)
    +
    + 	if (open_ok)
    + 		graph = load_commit_graph_one_fd_st(fd, &st);
    +-	 else
    +-		graph = read_commit_graph_one(the_repository, opts.obj_dir);
    ++	else
    ++		graph = read_commit_graph_one(the_repository, odb->path);
    +
    + 	/* Return failure if open_ok predicted success */
    + 	if (!graph)
     @@ builtin/commit-graph.c: static int graph_write(int argc, const char **argv)
    - 	odb = find_odb_or_die(the_repository, opts.obj_dir);
    + {
    + 	struct string_list *pack_indexes = NULL;
    + 	struct string_list *commit_hex = NULL;
    ++	struct object_directory *odb = NULL;
    + 	struct string_list lines;
    + 	int result = 0;
    + 	enum commit_graph_write_flags flags = 0;
    +@@ builtin/commit-graph.c: static int graph_write(int argc, const char **argv)
    + 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
    +
    + 	read_replace_refs = 0;
    ++	odb = find_odb(the_repository, opts.obj_dir);

      	if (opts.reachable) {
    --		if (write_commit_graph_reachable(odb->path, flags, &split_opts))
    +-		if (write_commit_graph_reachable(opts.obj_dir, flags, &split_opts))
     +		if (write_commit_graph_reachable(odb, flags, &split_opts))
      			return 1;
      		return 0;
    @@ builtin/commit-graph.c: static int graph_write(int argc, const char **argv)
      		UNLEAK(buf);
      	}

    --	if (write_commit_graph(odb->path,
    +-	if (write_commit_graph(opts.obj_dir,
     +	if (write_commit_graph(odb,
      			       pack_indexes,
      			       commit_hex,
    @@ commit-graph.c: static void split_graph_merge_strategy(struct write_commit_graph

      	while (g && (g->num_commits <= size_mult * num_commits ||
      		    (max_commits && num_commits > max_commits))) {
    --		if (strcmp(g->odb->path, ctx->obj_dir))
    -+		if (strcmp(g->odb->path, ctx->odb->path))
    +-		if (strcmp(g->obj_dir, ctx->obj_dir))
    ++		if (strcmp(g->obj_dir, ctx->odb->path))
      			break;

      		num_commits += g->num_commits;
     @@ commit-graph.c: static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
    - 		char *old_graph_name = get_commit_graph_filename(g->odb->path);
    + 		char *old_graph_name = get_commit_graph_filename(g->obj_dir);

      		if (!strcmp(g->filename, old_graph_name) &&
    --		    strcmp(g->odb->path, ctx->obj_dir)) {
    -+		    strcmp(g->odb->path, ctx->odb->path)) {
    +-		    strcmp(g->obj_dir, ctx->obj_dir)) {
    ++		    strcmp(g->obj_dir, ctx->odb->path)) {
      			ctx->num_commit_graphs_after = 1;
      			ctx->new_base_graph = NULL;
      		}
    @@ commit-graph.c: int write_commit_graph(const char *obj_dir,
      		ctx->oids.alloc = split_opts->max_commits;

      	if (ctx->append) {
    --		struct object_directory *odb = find_odb(ctx->r, ctx->obj_dir);
    --		prepare_commit_graph_one(ctx->r, odb);
    -+		prepare_commit_graph_one(ctx->r, ctx->odb);
    +-		prepare_commit_graph_one(ctx->r, ctx->obj_dir);
    ++		prepare_commit_graph_one(ctx->r, ctx->odb->path);
      		if (ctx->r->objects->commit_graph)
      			ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
      	}
    @@ commit-graph.c: int write_commit_graph(const char *obj_dir,
      		for (i = 0; i < ctx->num_commit_graphs_after; i++) {

      ## commit-graph.h ##
    +@@
    + #include "repository.h"
    + #include "string-list.h"
    + #include "cache.h"
    ++#include "object-store.h"
    +
    + #define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
    + #define GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD "GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD"
     @@ commit-graph.h: struct split_commit_graph_opts {
       * is not compatible with the commit-graph feature, then the
       * methods will return 0 without writing a commit-graph.
2:  328884f5f6 ! 3:  5fd5cfca6e commit-graph.h: store object directory in 'struct commit_graph'
    @@ Metadata
      ## Commit message ##
         commit-graph.h: store object directory in 'struct commit_graph'

    -    There are lots of places in 'commit-graph.h' where a function either has
    -    (or almost has) a full 'struct object_directory *', accesses '->path',
    -    and then throws away the rest of the struct.
    +    In a previous patch, the 'char *object_dir' in 'struct commit_graph' was
    +    replaced with a 'struct object_directory'. This patch applies the same
    +    treatment to 'struct commit_graph', which is another intermediate step
    +    towards getting rid of all path normalization in 'commit-graph.c'.

    -    This can cause headaches when comparing the locations of object
    -    directories across alternates (e.g., in the case of deciding if two
    -    commit-graph layers can be merged). These paths are normalized with
    -    'normalize_path_copy()' which mitigates some comparison issues, but not
    -    all [1].
    +    Instead of taking a 'char *object_dir', functions that construct a
    +    'struct commit_graph' now take a 'struct object_directory *'. Any code
    +    that needs an object directory path use '->path' instead.

    -    Instead of getting rid of the 'struct object_directory *', store that
    -    insead of a 'char *odb' in 'struct commit_graph'. Once the 'struct
    -    write_commit_graph_context' has an object_directory pointer, too, this
    -    will allow calling code to replace these error-prone path comparisons
    -    with raw pointer comparisons, thereby circumventing any
    -    normalization-related errors. This will be introduced in a subsequent
    -    patch.
    -
    -    [1]: In my testing, for example, I can get one side of the commit-graph
    -    code to fill object_dir with "./objects" and the other with just
    -    "objects".
    +    This ensures that all calls to functions that perform path normalization
    +    are given arguments which do not themselves require normalization. This
    +    prepares those functions to drop their normalization entirely, which
    +    will occur in the subsequent patch.

         Signed-off-by: Taylor Blau <me@ttaylorr.com>

      ## builtin/commit-graph.c ##
     @@ builtin/commit-graph.c: static int graph_verify(int argc, const char **argv)
    -
      	if (open_ok)
      		graph = load_commit_graph_one_fd_st(fd, &st);
    --	 else
    --		graph = read_commit_graph_one(the_repository, opts.obj_dir);
    -+	else {
    -+		struct object_directory *odb;
    -+		if ((odb = find_odb(the_repository, opts.obj_dir)))
    -+			graph = read_commit_graph_one(the_repository, odb);
    -+	}
    + 	else
    +-		graph = read_commit_graph_one(the_repository, odb->path);
    ++		graph = read_commit_graph_one(the_repository, odb);

      	/* Return failure if open_ok predicted success */
      	if (!graph)
    -@@ builtin/commit-graph.c: static int graph_write(int argc, const char **argv)
    - 	struct string_list lines;
    - 	int result = 0;
    - 	enum commit_graph_write_flags flags = 0;
    -+	struct object_directory *odb = NULL;
    -
    - 	static struct option builtin_commit_graph_write_options[] = {
    - 		OPT_STRING(0, "object-dir", &opts.obj_dir,
    -@@ builtin/commit-graph.c: static int graph_write(int argc, const char **argv)
    - 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
    -
    - 	read_replace_refs = 0;
    -+	odb = find_odb(the_repository, opts.obj_dir);
    -
    - 	if (opts.reachable) {
    --		if (write_commit_graph_reachable(opts.obj_dir, flags, &split_opts))
    -+		if (write_commit_graph_reachable(odb->path, flags, &split_opts))
    - 			return 1;
    - 		return 0;
    - 	}
    -@@ builtin/commit-graph.c: static int graph_write(int argc, const char **argv)
    - 		UNLEAK(buf);
    - 	}
    -
    --	if (write_commit_graph(opts.obj_dir,
    -+	if (write_commit_graph(odb->path,
    - 			       pack_indexes,
    - 			       commit_hex,
    - 			       flags,
    -
    - ## builtin/commit.c ##
    -@@
    - #include "help.h"
    - #include "commit-reach.h"
    - #include "commit-graph.h"
    -+#include "object-store.h"
    -
    - static const char * const builtin_commit_usage[] = {
    - 	N_("git commit [<options>] [--] <pathspec>..."),

      ## commit-graph.c ##
    -@@ commit-graph.c: static uint8_t oid_version(void)
    - 	return 1;
    - }
    -
    -+struct object_directory *find_odb(struct repository *r, const char *obj_dir)
    -+{
    -+	struct object_directory *odb;
    -+	char *obj_dir_real = real_pathdup(obj_dir, 1);
    -+	int cmp = -1;
    -+
    -+	prepare_alt_odb(r);
    -+	for (odb = r->objects->odb; odb; odb = odb->next) {
    -+		cmp = strcmp(obj_dir_real, real_path(odb->path));
    -+		if (!cmp)
    -+			break;
    -+	}
    -+
    -+	free(obj_dir_real);
    -+
    -+	if (cmp)
    -+		odb = NULL;
    -+	return odb;
    -+}
    -+
    - static struct commit_graph *alloc_commit_graph(void)
    - {
    - 	struct commit_graph *g = xcalloc(1, sizeof(*g));
     @@ commit-graph.c: static struct commit_graph *load_commit_graph_one(const char *graph_file)
      	return g;
      }
    @@ commit-graph.c: static void split_graph_merge_strategy(struct write_commit_graph

      	while (g && (g->num_commits <= size_mult * num_commits ||
      		    (max_commits && num_commits > max_commits))) {
    --		if (strcmp(g->obj_dir, ctx->obj_dir))
    -+		if (strcmp(g->odb->path, ctx->obj_dir))
    +-		if (strcmp(g->obj_dir, ctx->odb->path))
    ++		if (strcmp(g->odb->path, ctx->odb->path))
      			break;

      		num_commits += g->num_commits;
    @@ commit-graph.c: static void split_graph_merge_strategy(struct write_commit_graph
     +		char *old_graph_name = get_commit_graph_filename(g->odb->path);

      		if (!strcmp(g->filename, old_graph_name) &&
    --		    strcmp(g->obj_dir, ctx->obj_dir)) {
    -+		    strcmp(g->odb->path, ctx->obj_dir)) {
    +-		    strcmp(g->obj_dir, ctx->odb->path)) {
    ++		    strcmp(g->odb->path, ctx->odb->path)) {
      			ctx->num_commit_graphs_after = 1;
      			ctx->new_base_graph = NULL;
      		}
    -@@ commit-graph.c: int write_commit_graph(const char *obj_dir,
    +@@ commit-graph.c: int write_commit_graph(struct object_directory *odb,
      		ctx->oids.alloc = split_opts->max_commits;

      	if (ctx->append) {
    --		prepare_commit_graph_one(ctx->r, ctx->obj_dir);
    -+		struct object_directory *odb = find_odb(ctx->r, ctx->obj_dir);
    -+		prepare_commit_graph_one(ctx->r, odb);
    +-		prepare_commit_graph_one(ctx->r, ctx->odb->path);
    ++		prepare_commit_graph_one(ctx->r, ctx->odb);
      		if (ctx->r->objects->commit_graph)
      			ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
      	}

      ## commit-graph.h ##
    -@@
    - #include "repository.h"
    - #include "string-list.h"
    - #include "cache.h"
    -+#include "object-store.h"
    -
    - #define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
    - #define GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD "GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD"
    -@@ commit-graph.h: struct commit;
    - char *get_commit_graph_filename(const char *obj_dir);
    - int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
    -
    -+struct object_directory *find_odb(struct repository *r, const char *obj_dir);
    -+
    - /*
    -  * Given a commit struct, try to fill the commit struct info, including:
    -  *  1. tree object
     @@ commit-graph.h: struct commit_graph {
      	uint32_t num_commits;
      	struct object_id oid;
3:  ce884d7742 < -:  ---------- builtin/commit-graph.c: die() with unknown '--object-dir'
5:  c9b2ba46ab ! 4:  f14e95aa7e commit-graph.c: remove path normalization, comparison
    @@ Commit message
         Signed-off-by: Taylor Blau <me@ttaylorr.com>

      ## builtin/commit-graph.c ##
    -@@ builtin/commit-graph.c: static struct object_directory *find_odb_or_die(struct repository *r,
    - static int graph_verify(int argc, const char **argv)
    - {
    - 	struct commit_graph *graph = NULL;
    -+	struct object_directory *odb = NULL;
    - 	char *graph_name;
    - 	int open_ok;
    - 	int fd;
     @@ builtin/commit-graph.c: static int graph_verify(int argc, const char **argv)
    - 	if (opts.progress)
      		flags |= COMMIT_GRAPH_WRITE_PROGRESS;

    --	graph_name = get_commit_graph_filename(opts.obj_dir);
    -+	odb = find_odb_or_die(the_repository, opts.obj_dir);
    + 	odb = find_odb(the_repository, opts.obj_dir);
    +-	graph_name = get_commit_graph_filename(odb->path);
     +	graph_name = get_commit_graph_filename(odb);
      	open_ok = open_commit_graph(graph_name, &fd, &st);
      	if (!open_ok && errno != ENOENT)
      		die_errno(_("Could not open commit-graph '%s'"), graph_name);
    -@@ builtin/commit-graph.c: static int graph_verify(int argc, const char **argv)
    -
    - 	if (open_ok)
    - 		graph = load_commit_graph_one_fd_st(fd, &st);
    --	else {
    --		struct object_directory *odb;
    --		if ((odb = find_odb_or_die(the_repository, opts.obj_dir)))
    --			graph = read_commit_graph_one(the_repository, odb);
    --	}
    -+	else
    -+		graph = read_commit_graph_one(the_repository, odb);
    -
    - 	/* Return failure if open_ok predicted success */
    - 	if (!graph)

      ## commit-graph.c ##
     @@
    @@ commit-graph.h
     +char *get_commit_graph_filename(struct object_directory *odb);
      int open_commit_graph(const char *graph_file, int *fd, struct stat *st);

    - struct object_directory *find_odb(struct repository *r, const char *obj_dir);
    + /*

      ## t/helper/test-read-graph.c ##
     @@ t/helper/test-read-graph.c: int cmd__read_graph(int argc, const char **argv)
6:  e70483f771 = 5:  aa12b7378b commit-graph.h: use odb in 'load_commit_graph_one_fd_st'
--
2.25.0.119.gaa12b7378b

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v2 1/5] t5318: don't pass non-object directory to '--object-dir'
  2020-02-03 21:17 ` [PATCH v2 0/5] " Taylor Blau
@ 2020-02-03 21:17   ` Taylor Blau
  2020-02-03 21:17   ` [PATCH v2 2/5] commit-graph.h: store an odb in 'struct write_commit_graph_context' Taylor Blau
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 28+ messages in thread
From: Taylor Blau @ 2020-02-03 21:17 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, martin.agren

In f237c8b6fe (commit-graph: implement git-commit-graph write,
2018-04-02) the test t5318.3 was introduced to ensure that calling 'git
commit-graph write' in a repository with no packfiles does not write any
commit-graph file(s).

To exercise more paths in 'builtin/commit-graph.c', this test passes
'--object-dir' to 'git commit-graph write', but the given argument
refers to the working copy, not the object directory.

Since the commit-graph sub-commands currently swallow these errors, this
does not result in a test failure. But, it is only lucky that the test
ends with no commit-graphs, since there were none to begin with.

In preparation for a future commit where an '--object-dir' argument that
does not match a known object directory will print out a failure, let's
fix the test to still use '--object-dir', but pass the correct location
to the object store instead of '.'.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 t/t5318-commit-graph.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index 3f03de6018..0bf98b56ec 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -19,8 +19,8 @@ test_expect_success 'verify graph with no graph file' '
 
 test_expect_success 'write graph with no packs' '
 	cd "$TRASH_DIRECTORY/full" &&
-	git commit-graph write --object-dir . &&
-	test_path_is_missing info/commit-graph
+	git commit-graph write --object-dir $objdir &&
+	test_path_is_missing $objdir/info/commit-graph
 '
 
 test_expect_success 'exit with correct error on bad input to --stdin-packs' '
-- 
2.25.0.119.gaa12b7378b


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v2 2/5] commit-graph.h: store an odb in 'struct write_commit_graph_context'
  2020-02-03 21:17 ` [PATCH v2 0/5] " Taylor Blau
  2020-02-03 21:17   ` [PATCH v2 1/5] t5318: don't pass non-object directory to '--object-dir' Taylor Blau
@ 2020-02-03 21:17   ` Taylor Blau
  2020-02-04  5:51     ` Taylor Blau
  2020-02-03 21:18   ` [PATCH v2 3/5] commit-graph.h: store object directory in 'struct commit_graph' Taylor Blau
                     ` (3 subsequent siblings)
  5 siblings, 1 reply; 28+ messages in thread
From: Taylor Blau @ 2020-02-03 21:17 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, martin.agren

There are lots of places in 'commit-graph.h' where a function either has
(or almost has) a full 'struct object_directory *', accesses '->path',
and then throws away the rest of the struct.

This can cause headaches when comparing the locations of object
directories across alternates (e.g., in the case of deciding if two
commit-graph layers can be merged). These paths are normalized with
'normalize_path_copy()' which mitigates some comparison issues, but not
all [1].

Replace usage of 'char *object_dir' with 'odb->path' by storing a
'struct object_directory *' in the 'write_commit_graph_context'
structure. This is an intermediate step towards getting rid of all path
normalization in 'commit-graph.c'.

Resolving a user-provided '--object-dir' argument now requires that we
compare it to the known alternates for equality.  Prior to this patch,
an unknown '--object-dir' argument would silently exit with status zero.

This can clearly lead to unintended behavior, such as verifying
commit-graphs that aren't in a repository's own object store (or one of
its alternates), or causing a typo to mask a legitimate commit-graph
verification failure. Make this error non-silent by 'die()'-ing when the
given '--object-dir' does not match any known alternate object store.

[1]: In my testing, for example, I can get one side of the commit-graph
code to fill object_dir with "./objects" and the other with just
"objects".

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 Documentation/git-commit-graph.txt |  5 +++-
 builtin/commit-graph.c             | 32 +++++++++++++++++++----
 builtin/commit.c                   |  2 +-
 builtin/fetch.c                    |  2 +-
 builtin/gc.c                       |  2 +-
 commit-graph.c                     | 41 ++++++++++++------------------
 commit-graph.h                     |  5 ++--
 7 files changed, 53 insertions(+), 36 deletions(-)

diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index bcd85c1976..28d1fee505 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -26,7 +26,10 @@ OPTIONS
 	file. This parameter exists to specify the location of an alternate
 	that only has the objects directory, not a full `.git` directory. The
 	commit-graph file is expected to be in the `<dir>/info` directory and
-	the packfiles are expected to be in `<dir>/pack`.
+	the packfiles are expected to be in `<dir>/pack`. If the directory
+	could not be made into an absolute path, or does not match any known
+	object directory, `git commit-graph ...` will exit with non-zero
+	status.
 
 --[no-]progress::
 	Turn progress on/off explicitly. If neither is specified, progress is
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index e0c6fc4bbf..31b57e4e1d 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -34,9 +34,28 @@ static struct opts_commit_graph {
 	int progress;
 } opts;
 
+struct object_directory *find_odb(struct repository *r, const char *obj_dir)
+{
+	struct object_directory *odb;
+	char *obj_dir_real = real_pathdup(obj_dir, 1);
+
+	prepare_alt_odb(r);
+	for (odb = r->objects->odb; odb; odb = odb->next) {
+		if (!strcmp(obj_dir_real, real_path(odb->path)))
+			break;
+	}
+
+	free(obj_dir_real);
+
+	if (!odb)
+		die(_("could not find object directory matching %s"), obj_dir);
+	return odb;
+}
+
 static int graph_verify(int argc, const char **argv)
 {
 	struct commit_graph *graph = NULL;
+	struct object_directory *odb = NULL;
 	char *graph_name;
 	int open_ok;
 	int fd;
@@ -67,7 +86,8 @@ static int graph_verify(int argc, const char **argv)
 	if (opts.progress)
 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
 
-	graph_name = get_commit_graph_filename(opts.obj_dir);
+	odb = find_odb(the_repository, opts.obj_dir);
+	graph_name = get_commit_graph_filename(odb->path);
 	open_ok = open_commit_graph(graph_name, &fd, &st);
 	if (!open_ok && errno != ENOENT)
 		die_errno(_("Could not open commit-graph '%s'"), graph_name);
@@ -76,8 +96,8 @@ static int graph_verify(int argc, const char **argv)
 
 	if (open_ok)
 		graph = load_commit_graph_one_fd_st(fd, &st);
-	 else
-		graph = read_commit_graph_one(the_repository, opts.obj_dir);
+	else
+		graph = read_commit_graph_one(the_repository, odb->path);
 
 	/* Return failure if open_ok predicted success */
 	if (!graph)
@@ -94,6 +114,7 @@ static int graph_write(int argc, const char **argv)
 {
 	struct string_list *pack_indexes = NULL;
 	struct string_list *commit_hex = NULL;
+	struct object_directory *odb = NULL;
 	struct string_list lines;
 	int result = 0;
 	enum commit_graph_write_flags flags = 0;
@@ -145,9 +166,10 @@ static int graph_write(int argc, const char **argv)
 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
 
 	read_replace_refs = 0;
+	odb = find_odb(the_repository, opts.obj_dir);
 
 	if (opts.reachable) {
-		if (write_commit_graph_reachable(opts.obj_dir, flags, &split_opts))
+		if (write_commit_graph_reachable(odb, flags, &split_opts))
 			return 1;
 		return 0;
 	}
@@ -169,7 +191,7 @@ static int graph_write(int argc, const char **argv)
 		UNLEAK(buf);
 	}
 
-	if (write_commit_graph(opts.obj_dir,
+	if (write_commit_graph(odb,
 			       pack_indexes,
 			       commit_hex,
 			       flags,
diff --git a/builtin/commit.c b/builtin/commit.c
index 646e84547d..9e124aaa7b 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1689,7 +1689,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		      "not exceeded, and then \"git restore --staged :/\" to recover."));
 
 	if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
-	    write_commit_graph_reachable(get_object_directory(), 0, NULL))
+	    write_commit_graph_reachable(the_repository->objects->odb, 0, NULL))
 		return 1;
 
 	repo_rerere(the_repository, 0);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index b4c6d921d0..1ce16c96e9 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1870,7 +1870,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 		if (progress)
 			commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;
 
-		write_commit_graph_reachable(get_object_directory(),
+		write_commit_graph_reachable(the_repository->objects->odb,
 					     commit_graph_flags,
 					     NULL);
 	}
diff --git a/builtin/gc.c b/builtin/gc.c
index 3f76bf4aa7..8e0b9cf41b 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -686,7 +686,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 
 	prepare_repo_settings(the_repository);
 	if (the_repository->settings.gc_write_commit_graph == 1)
-		write_commit_graph_reachable(get_object_directory(),
+		write_commit_graph_reachable(the_repository->objects->odb,
 					     !quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
 					     NULL);
 
diff --git a/commit-graph.c b/commit-graph.c
index b205e65ed1..cbfeece112 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -772,7 +772,7 @@ struct packed_oid_list {
 
 struct write_commit_graph_context {
 	struct repository *r;
-	char *obj_dir;
+	struct object_directory *odb;
 	char *graph_name;
 	struct packed_oid_list oids;
 	struct packed_commit_list commits;
@@ -1149,7 +1149,7 @@ static int add_ref_to_list(const char *refname,
 	return 0;
 }
 
-int write_commit_graph_reachable(const char *obj_dir,
+int write_commit_graph_reachable(struct object_directory *odb,
 				 enum commit_graph_write_flags flags,
 				 const struct split_commit_graph_opts *split_opts)
 {
@@ -1157,7 +1157,7 @@ int write_commit_graph_reachable(const char *obj_dir,
 	int result;
 
 	for_each_ref(add_ref_to_list, &list);
-	result = write_commit_graph(obj_dir, NULL, &list,
+	result = write_commit_graph(odb, NULL, &list,
 				    flags, split_opts);
 
 	string_list_clear(&list, 0);
@@ -1172,7 +1172,7 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,
 	struct strbuf packname = STRBUF_INIT;
 	int dirlen;
 
-	strbuf_addf(&packname, "%s/pack/", ctx->obj_dir);
+	strbuf_addf(&packname, "%s/pack/", ctx->odb->path);
 	dirlen = packname.len;
 	if (ctx->report_progress) {
 		strbuf_addf(&progress_title,
@@ -1368,10 +1368,10 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 
 		strbuf_addf(&tmp_file,
 			    "%s/info/commit-graphs/tmp_graph_XXXXXX",
-			    ctx->obj_dir);
+			    ctx->odb->path);
 		ctx->graph_name = strbuf_detach(&tmp_file, NULL);
 	} else {
-		ctx->graph_name = get_commit_graph_filename(ctx->obj_dir);
+		ctx->graph_name = get_commit_graph_filename(ctx->odb->path);
 	}
 
 	if (safe_create_leading_directories(ctx->graph_name)) {
@@ -1382,7 +1382,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 	}
 
 	if (ctx->split) {
-		char *lock_name = get_chain_filename(ctx->obj_dir);
+		char *lock_name = get_chain_filename(ctx->odb->path);
 
 		hold_lock_file_for_update(&lk, lock_name, LOCK_DIE_ON_ERROR);
 
@@ -1506,12 +1506,12 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 				}
 			}
 		} else {
-			char *graph_name = get_commit_graph_filename(ctx->obj_dir);
+			char *graph_name = get_commit_graph_filename(ctx->odb->path);
 			unlink(graph_name);
 		}
 
 		ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(oid_to_hex(&file_hash));
-		final_graph_name = get_split_graph_filename(ctx->obj_dir,
+		final_graph_name = get_split_graph_filename(ctx->odb->path,
 					ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
 		ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name;
 
@@ -1553,7 +1553,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 
 	while (g && (g->num_commits <= size_mult * num_commits ||
 		    (max_commits && num_commits > max_commits))) {
-		if (strcmp(g->obj_dir, ctx->obj_dir))
+		if (strcmp(g->obj_dir, ctx->odb->path))
 			break;
 
 		num_commits += g->num_commits;
@@ -1568,7 +1568,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 		char *old_graph_name = get_commit_graph_filename(g->obj_dir);
 
 		if (!strcmp(g->filename, old_graph_name) &&
-		    strcmp(g->obj_dir, ctx->obj_dir)) {
+		    strcmp(g->obj_dir, ctx->odb->path)) {
 			ctx->num_commit_graphs_after = 1;
 			ctx->new_base_graph = NULL;
 		}
@@ -1719,13 +1719,13 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
 	if (ctx->split_opts && ctx->split_opts->expire_time)
 		expire_time -= ctx->split_opts->expire_time;
 	if (!ctx->split) {
-		char *chain_file_name = get_chain_filename(ctx->obj_dir);
+		char *chain_file_name = get_chain_filename(ctx->odb->path);
 		unlink(chain_file_name);
 		free(chain_file_name);
 		ctx->num_commit_graphs_after = 0;
 	}
 
-	strbuf_addstr(&path, ctx->obj_dir);
+	strbuf_addstr(&path, ctx->odb->path);
 	strbuf_addstr(&path, "/info/commit-graphs");
 	dir = opendir(path.buf);
 
@@ -1764,7 +1764,7 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
 	strbuf_release(&path);
 }
 
-int write_commit_graph(const char *obj_dir,
+int write_commit_graph(struct object_directory *odb,
 		       struct string_list *pack_indexes,
 		       struct string_list *commit_hex,
 		       enum commit_graph_write_flags flags,
@@ -1772,7 +1772,6 @@ int write_commit_graph(const char *obj_dir,
 {
 	struct write_commit_graph_context *ctx;
 	uint32_t i, count_distinct = 0;
-	size_t len;
 	int res = 0;
 
 	if (!commit_graph_compatible(the_repository))
@@ -1780,14 +1779,7 @@ int write_commit_graph(const char *obj_dir,
 
 	ctx = xcalloc(1, sizeof(struct write_commit_graph_context));
 	ctx->r = the_repository;
-
-	/* normalize object dir with no trailing slash */
-	ctx->obj_dir = xmallocz(strlen(obj_dir) + 1);
-	normalize_path_copy(ctx->obj_dir, obj_dir);
-	len = strlen(ctx->obj_dir);
-	if (len && ctx->obj_dir[len - 1] == '/')
-		ctx->obj_dir[len - 1] = 0;
-
+	ctx->odb = odb;
 	ctx->append = flags & COMMIT_GRAPH_WRITE_APPEND ? 1 : 0;
 	ctx->report_progress = flags & COMMIT_GRAPH_WRITE_PROGRESS ? 1 : 0;
 	ctx->split = flags & COMMIT_GRAPH_WRITE_SPLIT ? 1 : 0;
@@ -1824,7 +1816,7 @@ int write_commit_graph(const char *obj_dir,
 		ctx->oids.alloc = split_opts->max_commits;
 
 	if (ctx->append) {
-		prepare_commit_graph_one(ctx->r, ctx->obj_dir);
+		prepare_commit_graph_one(ctx->r, ctx->odb->path);
 		if (ctx->r->objects->commit_graph)
 			ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
 	}
@@ -1898,7 +1890,6 @@ int write_commit_graph(const char *obj_dir,
 	free(ctx->graph_name);
 	free(ctx->commits.list);
 	free(ctx->oids.list);
-	free(ctx->obj_dir);
 
 	if (ctx->commit_graph_filenames_after) {
 		for (i = 0; i < ctx->num_commit_graphs_after; i++) {
diff --git a/commit-graph.h b/commit-graph.h
index 7f5c933fa2..2a6251bd3d 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -5,6 +5,7 @@
 #include "repository.h"
 #include "string-list.h"
 #include "cache.h"
+#include "object-store.h"
 
 #define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
 #define GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD "GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD"
@@ -91,10 +92,10 @@ struct split_commit_graph_opts {
  * is not compatible with the commit-graph feature, then the
  * methods will return 0 without writing a commit-graph.
  */
-int write_commit_graph_reachable(const char *obj_dir,
+int write_commit_graph_reachable(struct object_directory *odb,
 				 enum commit_graph_write_flags flags,
 				 const struct split_commit_graph_opts *split_opts);
-int write_commit_graph(const char *obj_dir,
+int write_commit_graph(struct object_directory *odb,
 		       struct string_list *pack_indexes,
 		       struct string_list *commit_hex,
 		       enum commit_graph_write_flags flags,
-- 
2.25.0.119.gaa12b7378b


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v2 3/5] commit-graph.h: store object directory in 'struct commit_graph'
  2020-02-03 21:17 ` [PATCH v2 0/5] " Taylor Blau
  2020-02-03 21:17   ` [PATCH v2 1/5] t5318: don't pass non-object directory to '--object-dir' Taylor Blau
  2020-02-03 21:17   ` [PATCH v2 2/5] commit-graph.h: store an odb in 'struct write_commit_graph_context' Taylor Blau
@ 2020-02-03 21:18   ` Taylor Blau
  2020-02-03 21:18   ` [PATCH v2 4/5] commit-graph.c: remove path normalization, comparison Taylor Blau
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 28+ messages in thread
From: Taylor Blau @ 2020-02-03 21:18 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, martin.agren

In a previous patch, the 'char *object_dir' in 'struct commit_graph' was
replaced with a 'struct object_directory'. This patch applies the same
treatment to 'struct commit_graph', which is another intermediate step
towards getting rid of all path normalization in 'commit-graph.c'.

Instead of taking a 'char *object_dir', functions that construct a
'struct commit_graph' now take a 'struct object_directory *'. Any code
that needs an object directory path use '->path' instead.

This ensures that all calls to functions that perform path normalization
are given arguments which do not themselves require normalization. This
prepares those functions to drop their normalization entirely, which
will occur in the subsequent patch.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 builtin/commit-graph.c |  2 +-
 commit-graph.c         | 38 +++++++++++++++++++++-----------------
 commit-graph.h         |  5 +++--
 3 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 31b57e4e1d..3501d9077b 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -97,7 +97,7 @@ static int graph_verify(int argc, const char **argv)
 	if (open_ok)
 		graph = load_commit_graph_one_fd_st(fd, &st);
 	else
-		graph = read_commit_graph_one(the_repository, odb->path);
+		graph = read_commit_graph_one(the_repository, odb);
 
 	/* Return failure if open_ok predicted success */
 	if (!graph)
diff --git a/commit-graph.c b/commit-graph.c
index cbfeece112..3af4a721ee 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -327,14 +327,15 @@ static struct commit_graph *load_commit_graph_one(const char *graph_file)
 	return g;
 }
 
-static struct commit_graph *load_commit_graph_v1(struct repository *r, const char *obj_dir)
+static struct commit_graph *load_commit_graph_v1(struct repository *r,
+						 struct object_directory *odb)
 {
-	char *graph_name = get_commit_graph_filename(obj_dir);
+	char *graph_name = get_commit_graph_filename(odb->path);
 	struct commit_graph *g = load_commit_graph_one(graph_name);
 	free(graph_name);
 
 	if (g)
-		g->obj_dir = obj_dir;
+		g->odb = odb;
 
 	return g;
 }
@@ -372,14 +373,15 @@ static int add_graph_to_chain(struct commit_graph *g,
 	return 1;
 }
 
-static struct commit_graph *load_commit_graph_chain(struct repository *r, const char *obj_dir)
+static struct commit_graph *load_commit_graph_chain(struct repository *r,
+						    struct object_directory *odb)
 {
 	struct commit_graph *graph_chain = NULL;
 	struct strbuf line = STRBUF_INIT;
 	struct stat st;
 	struct object_id *oids;
 	int i = 0, valid = 1, count;
-	char *chain_name = get_chain_filename(obj_dir);
+	char *chain_name = get_chain_filename(odb->path);
 	FILE *fp;
 	int stat_res;
 
@@ -418,7 +420,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r, const
 			free(graph_name);
 
 			if (g) {
-				g->obj_dir = odb->path;
+				g->odb = odb;
 
 				if (add_graph_to_chain(g, graph_chain, oids, i)) {
 					graph_chain = g;
@@ -442,23 +444,25 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r, const
 	return graph_chain;
 }
 
-struct commit_graph *read_commit_graph_one(struct repository *r, const char *obj_dir)
+struct commit_graph *read_commit_graph_one(struct repository *r,
+					   struct object_directory *odb)
 {
-	struct commit_graph *g = load_commit_graph_v1(r, obj_dir);
+	struct commit_graph *g = load_commit_graph_v1(r, odb);
 
 	if (!g)
-		g = load_commit_graph_chain(r, obj_dir);
+		g = load_commit_graph_chain(r, odb);
 
 	return g;
 }
 
-static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
+static void prepare_commit_graph_one(struct repository *r,
+				     struct object_directory *odb)
 {
 
 	if (r->objects->commit_graph)
 		return;
 
-	r->objects->commit_graph = read_commit_graph_one(r, obj_dir);
+	r->objects->commit_graph = read_commit_graph_one(r, odb);
 }
 
 /*
@@ -505,7 +509,7 @@ static int prepare_commit_graph(struct repository *r)
 	for (odb = r->objects->odb;
 	     !r->objects->commit_graph && odb;
 	     odb = odb->next)
-		prepare_commit_graph_one(r, odb->path);
+		prepare_commit_graph_one(r, odb);
 	return !!r->objects->commit_graph;
 }
 
@@ -1470,7 +1474,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 
 	if (ctx->split && ctx->base_graph_name && ctx->num_commit_graphs_after > 1) {
 		char *new_base_hash = xstrdup(oid_to_hex(&ctx->new_base_graph->oid));
-		char *new_base_name = get_split_graph_filename(ctx->new_base_graph->obj_dir, new_base_hash);
+		char *new_base_name = get_split_graph_filename(ctx->new_base_graph->odb->path, new_base_hash);
 
 		free(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 2]);
 		free(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 2]);
@@ -1553,7 +1557,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 
 	while (g && (g->num_commits <= size_mult * num_commits ||
 		    (max_commits && num_commits > max_commits))) {
-		if (strcmp(g->obj_dir, ctx->odb->path))
+		if (strcmp(g->odb->path, ctx->odb->path))
 			break;
 
 		num_commits += g->num_commits;
@@ -1565,10 +1569,10 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 	ctx->new_base_graph = g;
 
 	if (ctx->num_commit_graphs_after == 2) {
-		char *old_graph_name = get_commit_graph_filename(g->obj_dir);
+		char *old_graph_name = get_commit_graph_filename(g->odb->path);
 
 		if (!strcmp(g->filename, old_graph_name) &&
-		    strcmp(g->obj_dir, ctx->odb->path)) {
+		    strcmp(g->odb->path, ctx->odb->path)) {
 			ctx->num_commit_graphs_after = 1;
 			ctx->new_base_graph = NULL;
 		}
@@ -1816,7 +1820,7 @@ int write_commit_graph(struct object_directory *odb,
 		ctx->oids.alloc = split_opts->max_commits;
 
 	if (ctx->append) {
-		prepare_commit_graph_one(ctx->r, ctx->odb->path);
+		prepare_commit_graph_one(ctx->r, ctx->odb);
 		if (ctx->r->objects->commit_graph)
 			ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
 	}
diff --git a/commit-graph.h b/commit-graph.h
index 2a6251bd3d..2448134378 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -49,7 +49,7 @@ struct commit_graph {
 	uint32_t num_commits;
 	struct object_id oid;
 	char *filename;
-	const char *obj_dir;
+	struct object_directory *odb;
 
 	uint32_t num_commits_in_base;
 	struct commit_graph *base_graph;
@@ -62,7 +62,8 @@ struct commit_graph {
 };
 
 struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st);
-struct commit_graph *read_commit_graph_one(struct repository *r, const char *obj_dir);
+struct commit_graph *read_commit_graph_one(struct repository *r,
+					   struct object_directory *odb);
 struct commit_graph *parse_commit_graph(void *graph_map, int fd,
 					size_t graph_size);
 
-- 
2.25.0.119.gaa12b7378b


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v2 4/5] commit-graph.c: remove path normalization, comparison
  2020-02-03 21:17 ` [PATCH v2 0/5] " Taylor Blau
                     ` (2 preceding siblings ...)
  2020-02-03 21:18   ` [PATCH v2 3/5] commit-graph.h: store object directory in 'struct commit_graph' Taylor Blau
@ 2020-02-03 21:18   ` Taylor Blau
  2020-02-03 21:18   ` [PATCH v2 5/5] commit-graph.h: use odb in 'load_commit_graph_one_fd_st' Taylor Blau
  2020-02-05 12:30   ` [PATCH v2 0/5] commit-graph: use 'struct object_directory *' everywhere Jeff King
  5 siblings, 0 replies; 28+ messages in thread
From: Taylor Blau @ 2020-02-03 21:18 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, martin.agren

As of the previous patch, all calls to 'commit-graph.c' functions which
perform path normalization (for e.g., 'get_commit_graph_filename()') are
of the form 'ctx->odb->path', which is always in normalized form.

Now that there are no callers passing non-normalized paths to these
functions, ensure that future callers are bound by the same restrictions
by making these functions take a 'struct object_directory *' instead of
a 'const char *'. To match, replace all calls with arguments of the form
'ctx->odb->path' with 'ctx->odb' To recover the path, functions that
perform path manipulation simply use 'odb->path'.

Further, avoid string comparisons with arguments of the form
'odb->path', and instead prefer raw pointer comparisons, which
accomplish the same effect, but are far less brittle.

This has a pleasant side-effect of making these functions much more
robust to paths that cannot be normalized by 'normalize_path_copy()',
i.e., because they are outside of the current working directory.

For example, prior to this patch, Valgrind reports that the following
uninitialized memory read [1]:

  $ ( cd t && GIT_DIR=../.git valgrind git rev-parse HEAD^ )

because 'normalize_path_copy()' can't normalize '../.git' (since it's
relative to but above of the current working directory) [2].

By using a 'struct object_directory *' directly,
'get_commit_graph_filename()' does not need to normalize, because all
paths are relative to the current working directory since they are
always read from the '->path' of an object directory.

[1]: https://lore.kernel.org/git/20191027042116.GA5801@sigill.intra.peff.net.
[2]: The bug here is that 'get_commit_graph_filename()' returns the
     result of 'normalize_path_copy()' without checking the return
     value.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 builtin/commit-graph.c     |  2 +-
 commit-graph.c             | 47 +++++++++++++++-----------------------
 commit-graph.h             |  2 +-
 t/helper/test-read-graph.c |  6 ++---
 4 files changed, 24 insertions(+), 33 deletions(-)

diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 3501d9077b..b16eba2a7a 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -87,7 +87,7 @@ static int graph_verify(int argc, const char **argv)
 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
 
 	odb = find_odb(the_repository, opts.obj_dir);
-	graph_name = get_commit_graph_filename(odb->path);
+	graph_name = get_commit_graph_filename(odb);
 	open_ok = open_commit_graph(graph_name, &fd, &st);
 	if (!open_ok && errno != ENOENT)
 		die_errno(_("Could not open commit-graph '%s'"), graph_name);
diff --git a/commit-graph.c b/commit-graph.c
index 3af4a721ee..49541760b5 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -44,30 +44,21 @@
 /* Remember to update object flag allocation in object.h */
 #define REACHABLE       (1u<<15)
 
-char *get_commit_graph_filename(const char *obj_dir)
+char *get_commit_graph_filename(struct object_directory *odb)
 {
-	char *filename = xstrfmt("%s/info/commit-graph", obj_dir);
-	char *normalized = xmalloc(strlen(filename) + 1);
-	normalize_path_copy(normalized, filename);
-	free(filename);
-	return normalized;
+	return xstrfmt("%s/info/commit-graph", odb->path);
 }
 
-static char *get_split_graph_filename(const char *obj_dir,
+static char *get_split_graph_filename(struct object_directory *odb,
 				      const char *oid_hex)
 {
-	char *filename = xstrfmt("%s/info/commit-graphs/graph-%s.graph",
-				 obj_dir,
-				 oid_hex);
-	char *normalized = xmalloc(strlen(filename) + 1);
-	normalize_path_copy(normalized, filename);
-	free(filename);
-	return normalized;
+	return xstrfmt("%s/info/commit-graphs/graph-%s.graph", odb->path,
+		       oid_hex);
 }
 
-static char *get_chain_filename(const char *obj_dir)
+static char *get_chain_filename(struct object_directory *odb)
 {
-	return xstrfmt("%s/info/commit-graphs/commit-graph-chain", obj_dir);
+	return xstrfmt("%s/info/commit-graphs/commit-graph-chain", odb->path);
 }
 
 static uint8_t oid_version(void)
@@ -330,7 +321,7 @@ static struct commit_graph *load_commit_graph_one(const char *graph_file)
 static struct commit_graph *load_commit_graph_v1(struct repository *r,
 						 struct object_directory *odb)
 {
-	char *graph_name = get_commit_graph_filename(odb->path);
+	char *graph_name = get_commit_graph_filename(odb);
 	struct commit_graph *g = load_commit_graph_one(graph_name);
 	free(graph_name);
 
@@ -381,7 +372,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
 	struct stat st;
 	struct object_id *oids;
 	int i = 0, valid = 1, count;
-	char *chain_name = get_chain_filename(odb->path);
+	char *chain_name = get_chain_filename(odb);
 	FILE *fp;
 	int stat_res;
 
@@ -414,7 +405,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
 
 		valid = 0;
 		for (odb = r->objects->odb; odb; odb = odb->next) {
-			char *graph_name = get_split_graph_filename(odb->path, line.buf);
+			char *graph_name = get_split_graph_filename(odb, line.buf);
 			struct commit_graph *g = load_commit_graph_one(graph_name);
 
 			free(graph_name);
@@ -1375,7 +1366,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 			    ctx->odb->path);
 		ctx->graph_name = strbuf_detach(&tmp_file, NULL);
 	} else {
-		ctx->graph_name = get_commit_graph_filename(ctx->odb->path);
+		ctx->graph_name = get_commit_graph_filename(ctx->odb);
 	}
 
 	if (safe_create_leading_directories(ctx->graph_name)) {
@@ -1386,7 +1377,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 	}
 
 	if (ctx->split) {
-		char *lock_name = get_chain_filename(ctx->odb->path);
+		char *lock_name = get_chain_filename(ctx->odb);
 
 		hold_lock_file_for_update(&lk, lock_name, LOCK_DIE_ON_ERROR);
 
@@ -1474,7 +1465,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 
 	if (ctx->split && ctx->base_graph_name && ctx->num_commit_graphs_after > 1) {
 		char *new_base_hash = xstrdup(oid_to_hex(&ctx->new_base_graph->oid));
-		char *new_base_name = get_split_graph_filename(ctx->new_base_graph->odb->path, new_base_hash);
+		char *new_base_name = get_split_graph_filename(ctx->new_base_graph->odb, new_base_hash);
 
 		free(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 2]);
 		free(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 2]);
@@ -1510,12 +1501,12 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 				}
 			}
 		} else {
-			char *graph_name = get_commit_graph_filename(ctx->odb->path);
+			char *graph_name = get_commit_graph_filename(ctx->odb);
 			unlink(graph_name);
 		}
 
 		ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(oid_to_hex(&file_hash));
-		final_graph_name = get_split_graph_filename(ctx->odb->path,
+		final_graph_name = get_split_graph_filename(ctx->odb,
 					ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
 		ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name;
 
@@ -1557,7 +1548,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 
 	while (g && (g->num_commits <= size_mult * num_commits ||
 		    (max_commits && num_commits > max_commits))) {
-		if (strcmp(g->odb->path, ctx->odb->path))
+		if (g->odb != ctx->odb)
 			break;
 
 		num_commits += g->num_commits;
@@ -1569,10 +1560,10 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 	ctx->new_base_graph = g;
 
 	if (ctx->num_commit_graphs_after == 2) {
-		char *old_graph_name = get_commit_graph_filename(g->odb->path);
+		char *old_graph_name = get_commit_graph_filename(g->odb);
 
 		if (!strcmp(g->filename, old_graph_name) &&
-		    strcmp(g->odb->path, ctx->odb->path)) {
+		    g->odb != ctx->odb) {
 			ctx->num_commit_graphs_after = 1;
 			ctx->new_base_graph = NULL;
 		}
@@ -1723,7 +1714,7 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
 	if (ctx->split_opts && ctx->split_opts->expire_time)
 		expire_time -= ctx->split_opts->expire_time;
 	if (!ctx->split) {
-		char *chain_file_name = get_chain_filename(ctx->odb->path);
+		char *chain_file_name = get_chain_filename(ctx->odb);
 		unlink(chain_file_name);
 		free(chain_file_name);
 		ctx->num_commit_graphs_after = 0;
diff --git a/commit-graph.h b/commit-graph.h
index 2448134378..5a690723b0 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -12,7 +12,7 @@
 
 struct commit;
 
-char *get_commit_graph_filename(const char *obj_dir);
+char *get_commit_graph_filename(struct object_directory *odb);
 int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
 
 /*
diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c
index d2884efe0a..2c2f65f06c 100644
--- a/t/helper/test-read-graph.c
+++ b/t/helper/test-read-graph.c
@@ -11,12 +11,12 @@ int cmd__read_graph(int argc, const char **argv)
 	int open_ok;
 	int fd;
 	struct stat st;
-	const char *object_dir;
+	struct object_directory *odb;
 
 	setup_git_directory();
-	object_dir = get_object_directory();
+	odb = the_repository->objects->odb;
 
-	graph_name = get_commit_graph_filename(object_dir);
+	graph_name = get_commit_graph_filename(odb);
 
 	open_ok = open_commit_graph(graph_name, &fd, &st);
 	if (!open_ok)
-- 
2.25.0.119.gaa12b7378b


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v2 5/5] commit-graph.h: use odb in 'load_commit_graph_one_fd_st'
  2020-02-03 21:17 ` [PATCH v2 0/5] " Taylor Blau
                     ` (3 preceding siblings ...)
  2020-02-03 21:18   ` [PATCH v2 4/5] commit-graph.c: remove path normalization, comparison Taylor Blau
@ 2020-02-03 21:18   ` Taylor Blau
  2020-02-05 12:30   ` [PATCH v2 0/5] commit-graph: use 'struct object_directory *' everywhere Jeff King
  5 siblings, 0 replies; 28+ messages in thread
From: Taylor Blau @ 2020-02-03 21:18 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, martin.agren

Apply a similar treatment as in the previous patch to pass a 'struct
object_directory *' through the 'load_commit_graph_one_fd_st'
initializer, too.

This prevents a potential bug where a pointer comparison is made to a
NULL 'g->odb', which would cause the commit-graph machinery to think
that a pair of commit-graphs belonged to different alternates when in
fact they do not (i.e., in the case of no '--object-dir').

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 builtin/commit-graph.c     |  2 +-
 commit-graph.c             | 21 ++++++++++-----------
 commit-graph.h             |  3 ++-
 t/helper/test-read-graph.c |  2 +-
 4 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index b16eba2a7a..dd6ab84be8 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -95,7 +95,7 @@ static int graph_verify(int argc, const char **argv)
 	FREE_AND_NULL(graph_name);
 
 	if (open_ok)
-		graph = load_commit_graph_one_fd_st(fd, &st);
+		graph = load_commit_graph_one_fd_st(fd, &st, odb);
 	else
 		graph = read_commit_graph_one(the_repository, odb);
 
diff --git a/commit-graph.c b/commit-graph.c
index 49541760b5..656dd647d5 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -108,7 +108,8 @@ int open_commit_graph(const char *graph_file, int *fd, struct stat *st)
 	return 1;
 }
 
-struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st)
+struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st,
+						 struct object_directory *odb)
 {
 	void *graph_map;
 	size_t graph_size;
@@ -124,7 +125,9 @@ struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st)
 	graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
 	ret = parse_commit_graph(graph_map, fd, graph_size);
 
-	if (!ret) {
+	if (ret)
+		ret->odb = odb;
+	else {
 		munmap(graph_map, graph_size);
 		close(fd);
 	}
@@ -299,7 +302,8 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
 	return graph;
 }
 
-static struct commit_graph *load_commit_graph_one(const char *graph_file)
+static struct commit_graph *load_commit_graph_one(const char *graph_file,
+						  struct object_directory *odb)
 {
 
 	struct stat st;
@@ -310,7 +314,7 @@ static struct commit_graph *load_commit_graph_one(const char *graph_file)
 	if (!open_ok)
 		return NULL;
 
-	g = load_commit_graph_one_fd_st(fd, &st);
+	g = load_commit_graph_one_fd_st(fd, &st, odb);
 
 	if (g)
 		g->filename = xstrdup(graph_file);
@@ -322,12 +326,9 @@ static struct commit_graph *load_commit_graph_v1(struct repository *r,
 						 struct object_directory *odb)
 {
 	char *graph_name = get_commit_graph_filename(odb);
-	struct commit_graph *g = load_commit_graph_one(graph_name);
+	struct commit_graph *g = load_commit_graph_one(graph_name, odb);
 	free(graph_name);
 
-	if (g)
-		g->odb = odb;
-
 	return g;
 }
 
@@ -406,13 +407,11 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
 		valid = 0;
 		for (odb = r->objects->odb; odb; odb = odb->next) {
 			char *graph_name = get_split_graph_filename(odb, line.buf);
-			struct commit_graph *g = load_commit_graph_one(graph_name);
+			struct commit_graph *g = load_commit_graph_one(graph_name, odb);
 
 			free(graph_name);
 
 			if (g) {
-				g->odb = odb;
-
 				if (add_graph_to_chain(g, graph_chain, oids, i)) {
 					graph_chain = g;
 					valid = 1;
diff --git a/commit-graph.h b/commit-graph.h
index 5a690723b0..e87a6f6360 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -61,7 +61,8 @@ struct commit_graph {
 	const unsigned char *chunk_base_graphs;
 };
 
-struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st);
+struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st,
+						 struct object_directory *odb);
 struct commit_graph *read_commit_graph_one(struct repository *r,
 					   struct object_directory *odb);
 struct commit_graph *parse_commit_graph(void *graph_map, int fd,
diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c
index 2c2f65f06c..f8a461767c 100644
--- a/t/helper/test-read-graph.c
+++ b/t/helper/test-read-graph.c
@@ -22,7 +22,7 @@ int cmd__read_graph(int argc, const char **argv)
 	if (!open_ok)
 		die_errno(_("Could not open commit-graph '%s'"), graph_name);
 
-	graph = load_commit_graph_one_fd_st(fd, &st);
+	graph = load_commit_graph_one_fd_st(fd, &st, odb);
 	if (!graph)
 		return 1;
 
-- 
2.25.0.119.gaa12b7378b

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v2 2/5] commit-graph.h: store an odb in 'struct write_commit_graph_context'
  2020-02-03 21:17   ` [PATCH v2 2/5] commit-graph.h: store an odb in 'struct write_commit_graph_context' Taylor Blau
@ 2020-02-04  5:51     ` Taylor Blau
  2020-02-04 19:54       ` Junio C Hamano
  0 siblings, 1 reply; 28+ messages in thread
From: Taylor Blau @ 2020-02-04  5:51 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, martin.agren

Whoops. In v2, this patch introduces 'find_odb()' as a function in
'builtin/commit-graph.c', but does not declare it static. This causes
breakage in gcc with '-Wmissing-prototypes'. Here is a correct version
of the patch that does not cause such breakage.

-- 8< --

Subject: [PATCH v2 2/5] commit-graph.h: store an odb in 'struct

There are lots of places in 'commit-graph.h' where a function either has
(or almost has) a full 'struct object_directory *', accesses '->path',
and then throws away the rest of the struct.

This can cause headaches when comparing the locations of object
directories across alternates (e.g., in the case of deciding if two
commit-graph layers can be merged). These paths are normalized with
'normalize_path_copy()' which mitigates some comparison issues, but not
all [1].

Replace usage of 'char *object_dir' with 'odb->path' by storing a
'struct object_directory *' in the 'write_commit_graph_context'
structure. This is an intermediate step towards getting rid of all path
normalization in 'commit-graph.c'.

Resolving a user-provided '--object-dir' argument now requires that we
compare it to the known alternates for equality.  Prior to this patch,
an unknown '--object-dir' argument would silently exit with status zero.

This can clearly lead to unintended behavior, such as verifying
commit-graphs that aren't in a repository's own object store (or one of
its alternates), or causing a typo to mask a legitimate commit-graph
verification failure. Make this error non-silent by 'die()'-ing when the
given '--object-dir' does not match any known alternate object store.

[1]: In my testing, for example, I can get one side of the commit-graph
code to fill object_dir with "./objects" and the other with just
"objects".

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 Documentation/git-commit-graph.txt |  5 +++-
 builtin/commit-graph.c             | 33 ++++++++++++++++++++----
 builtin/commit.c                   |  2 +-
 builtin/fetch.c                    |  2 +-
 builtin/gc.c                       |  2 +-
 commit-graph.c                     | 41 ++++++++++++------------------
 commit-graph.h                     |  5 ++--
 7 files changed, 54 insertions(+), 36 deletions(-)

diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index bcd85c1976..28d1fee505 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -26,7 +26,10 @@ OPTIONS
 	file. This parameter exists to specify the location of an alternate
 	that only has the objects directory, not a full `.git` directory. The
 	commit-graph file is expected to be in the `<dir>/info` directory and
-	the packfiles are expected to be in `<dir>/pack`.
+	the packfiles are expected to be in `<dir>/pack`. If the directory
+	could not be made into an absolute path, or does not match any known
+	object directory, `git commit-graph ...` will exit with non-zero
+	status.

 --[no-]progress::
 	Turn progress on/off explicitly. If neither is specified, progress is
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index e0c6fc4bbf..20a3d31b76 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -34,9 +34,29 @@ static struct opts_commit_graph {
 	int progress;
 } opts;

+static struct object_directory *find_odb(struct repository *r,
+					 const char *obj_dir)
+{
+	struct object_directory *odb;
+	char *obj_dir_real = real_pathdup(obj_dir, 1);
+
+	prepare_alt_odb(r);
+	for (odb = r->objects->odb; odb; odb = odb->next) {
+		if (!strcmp(obj_dir_real, real_path(odb->path)))
+			break;
+	}
+
+	free(obj_dir_real);
+
+	if (!odb)
+		die(_("could not find object directory matching %s"), obj_dir);
+	return odb;
+}
+
 static int graph_verify(int argc, const char **argv)
 {
 	struct commit_graph *graph = NULL;
+	struct object_directory *odb = NULL;
 	char *graph_name;
 	int open_ok;
 	int fd;
@@ -67,7 +87,8 @@ static int graph_verify(int argc, const char **argv)
 	if (opts.progress)
 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;

-	graph_name = get_commit_graph_filename(opts.obj_dir);
+	odb = find_odb(the_repository, opts.obj_dir);
+	graph_name = get_commit_graph_filename(odb->path);
 	open_ok = open_commit_graph(graph_name, &fd, &st);
 	if (!open_ok && errno != ENOENT)
 		die_errno(_("Could not open commit-graph '%s'"), graph_name);
@@ -76,8 +97,8 @@ static int graph_verify(int argc, const char **argv)

 	if (open_ok)
 		graph = load_commit_graph_one_fd_st(fd, &st);
-	 else
-		graph = read_commit_graph_one(the_repository, opts.obj_dir);
+	else
+		graph = read_commit_graph_one(the_repository, odb->path);

 	/* Return failure if open_ok predicted success */
 	if (!graph)
@@ -94,6 +115,7 @@ static int graph_write(int argc, const char **argv)
 {
 	struct string_list *pack_indexes = NULL;
 	struct string_list *commit_hex = NULL;
+	struct object_directory *odb = NULL;
 	struct string_list lines;
 	int result = 0;
 	enum commit_graph_write_flags flags = 0;
@@ -145,9 +167,10 @@ static int graph_write(int argc, const char **argv)
 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;

 	read_replace_refs = 0;
+	odb = find_odb(the_repository, opts.obj_dir);

 	if (opts.reachable) {
-		if (write_commit_graph_reachable(opts.obj_dir, flags, &split_opts))
+		if (write_commit_graph_reachable(odb, flags, &split_opts))
 			return 1;
 		return 0;
 	}
@@ -169,7 +192,7 @@ static int graph_write(int argc, const char **argv)
 		UNLEAK(buf);
 	}

-	if (write_commit_graph(opts.obj_dir,
+	if (write_commit_graph(odb,
 			       pack_indexes,
 			       commit_hex,
 			       flags,
diff --git a/builtin/commit.c b/builtin/commit.c
index 646e84547d..9e124aaa7b 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1689,7 +1689,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 		      "not exceeded, and then \"git restore --staged :/\" to recover."));

 	if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
-	    write_commit_graph_reachable(get_object_directory(), 0, NULL))
+	    write_commit_graph_reachable(the_repository->objects->odb, 0, NULL))
 		return 1;

 	repo_rerere(the_repository, 0);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index b4c6d921d0..1ce16c96e9 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1870,7 +1870,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 		if (progress)
 			commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;

-		write_commit_graph_reachable(get_object_directory(),
+		write_commit_graph_reachable(the_repository->objects->odb,
 					     commit_graph_flags,
 					     NULL);
 	}
diff --git a/builtin/gc.c b/builtin/gc.c
index 3f76bf4aa7..8e0b9cf41b 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -686,7 +686,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)

 	prepare_repo_settings(the_repository);
 	if (the_repository->settings.gc_write_commit_graph == 1)
-		write_commit_graph_reachable(get_object_directory(),
+		write_commit_graph_reachable(the_repository->objects->odb,
 					     !quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
 					     NULL);

diff --git a/commit-graph.c b/commit-graph.c
index b205e65ed1..cbfeece112 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -772,7 +772,7 @@ struct packed_oid_list {

 struct write_commit_graph_context {
 	struct repository *r;
-	char *obj_dir;
+	struct object_directory *odb;
 	char *graph_name;
 	struct packed_oid_list oids;
 	struct packed_commit_list commits;
@@ -1149,7 +1149,7 @@ static int add_ref_to_list(const char *refname,
 	return 0;
 }

-int write_commit_graph_reachable(const char *obj_dir,
+int write_commit_graph_reachable(struct object_directory *odb,
 				 enum commit_graph_write_flags flags,
 				 const struct split_commit_graph_opts *split_opts)
 {
@@ -1157,7 +1157,7 @@ int write_commit_graph_reachable(const char *obj_dir,
 	int result;

 	for_each_ref(add_ref_to_list, &list);
-	result = write_commit_graph(obj_dir, NULL, &list,
+	result = write_commit_graph(odb, NULL, &list,
 				    flags, split_opts);

 	string_list_clear(&list, 0);
@@ -1172,7 +1172,7 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,
 	struct strbuf packname = STRBUF_INIT;
 	int dirlen;

-	strbuf_addf(&packname, "%s/pack/", ctx->obj_dir);
+	strbuf_addf(&packname, "%s/pack/", ctx->odb->path);
 	dirlen = packname.len;
 	if (ctx->report_progress) {
 		strbuf_addf(&progress_title,
@@ -1368,10 +1368,10 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)

 		strbuf_addf(&tmp_file,
 			    "%s/info/commit-graphs/tmp_graph_XXXXXX",
-			    ctx->obj_dir);
+			    ctx->odb->path);
 		ctx->graph_name = strbuf_detach(&tmp_file, NULL);
 	} else {
-		ctx->graph_name = get_commit_graph_filename(ctx->obj_dir);
+		ctx->graph_name = get_commit_graph_filename(ctx->odb->path);
 	}

 	if (safe_create_leading_directories(ctx->graph_name)) {
@@ -1382,7 +1382,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 	}

 	if (ctx->split) {
-		char *lock_name = get_chain_filename(ctx->obj_dir);
+		char *lock_name = get_chain_filename(ctx->odb->path);

 		hold_lock_file_for_update(&lk, lock_name, LOCK_DIE_ON_ERROR);

@@ -1506,12 +1506,12 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 				}
 			}
 		} else {
-			char *graph_name = get_commit_graph_filename(ctx->obj_dir);
+			char *graph_name = get_commit_graph_filename(ctx->odb->path);
 			unlink(graph_name);
 		}

 		ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(oid_to_hex(&file_hash));
-		final_graph_name = get_split_graph_filename(ctx->obj_dir,
+		final_graph_name = get_split_graph_filename(ctx->odb->path,
 					ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
 		ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name;

@@ -1553,7 +1553,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)

 	while (g && (g->num_commits <= size_mult * num_commits ||
 		    (max_commits && num_commits > max_commits))) {
-		if (strcmp(g->obj_dir, ctx->obj_dir))
+		if (strcmp(g->obj_dir, ctx->odb->path))
 			break;

 		num_commits += g->num_commits;
@@ -1568,7 +1568,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 		char *old_graph_name = get_commit_graph_filename(g->obj_dir);

 		if (!strcmp(g->filename, old_graph_name) &&
-		    strcmp(g->obj_dir, ctx->obj_dir)) {
+		    strcmp(g->obj_dir, ctx->odb->path)) {
 			ctx->num_commit_graphs_after = 1;
 			ctx->new_base_graph = NULL;
 		}
@@ -1719,13 +1719,13 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
 	if (ctx->split_opts && ctx->split_opts->expire_time)
 		expire_time -= ctx->split_opts->expire_time;
 	if (!ctx->split) {
-		char *chain_file_name = get_chain_filename(ctx->obj_dir);
+		char *chain_file_name = get_chain_filename(ctx->odb->path);
 		unlink(chain_file_name);
 		free(chain_file_name);
 		ctx->num_commit_graphs_after = 0;
 	}

-	strbuf_addstr(&path, ctx->obj_dir);
+	strbuf_addstr(&path, ctx->odb->path);
 	strbuf_addstr(&path, "/info/commit-graphs");
 	dir = opendir(path.buf);

@@ -1764,7 +1764,7 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
 	strbuf_release(&path);
 }

-int write_commit_graph(const char *obj_dir,
+int write_commit_graph(struct object_directory *odb,
 		       struct string_list *pack_indexes,
 		       struct string_list *commit_hex,
 		       enum commit_graph_write_flags flags,
@@ -1772,7 +1772,6 @@ int write_commit_graph(const char *obj_dir,
 {
 	struct write_commit_graph_context *ctx;
 	uint32_t i, count_distinct = 0;
-	size_t len;
 	int res = 0;

 	if (!commit_graph_compatible(the_repository))
@@ -1780,14 +1779,7 @@ int write_commit_graph(const char *obj_dir,

 	ctx = xcalloc(1, sizeof(struct write_commit_graph_context));
 	ctx->r = the_repository;
-
-	/* normalize object dir with no trailing slash */
-	ctx->obj_dir = xmallocz(strlen(obj_dir) + 1);
-	normalize_path_copy(ctx->obj_dir, obj_dir);
-	len = strlen(ctx->obj_dir);
-	if (len && ctx->obj_dir[len - 1] == '/')
-		ctx->obj_dir[len - 1] = 0;
-
+	ctx->odb = odb;
 	ctx->append = flags & COMMIT_GRAPH_WRITE_APPEND ? 1 : 0;
 	ctx->report_progress = flags & COMMIT_GRAPH_WRITE_PROGRESS ? 1 : 0;
 	ctx->split = flags & COMMIT_GRAPH_WRITE_SPLIT ? 1 : 0;
@@ -1824,7 +1816,7 @@ int write_commit_graph(const char *obj_dir,
 		ctx->oids.alloc = split_opts->max_commits;

 	if (ctx->append) {
-		prepare_commit_graph_one(ctx->r, ctx->obj_dir);
+		prepare_commit_graph_one(ctx->r, ctx->odb->path);
 		if (ctx->r->objects->commit_graph)
 			ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
 	}
@@ -1898,7 +1890,6 @@ int write_commit_graph(const char *obj_dir,
 	free(ctx->graph_name);
 	free(ctx->commits.list);
 	free(ctx->oids.list);
-	free(ctx->obj_dir);

 	if (ctx->commit_graph_filenames_after) {
 		for (i = 0; i < ctx->num_commit_graphs_after; i++) {
diff --git a/commit-graph.h b/commit-graph.h
index 7f5c933fa2..2a6251bd3d 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -5,6 +5,7 @@
 #include "repository.h"
 #include "string-list.h"
 #include "cache.h"
+#include "object-store.h"

 #define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
 #define GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD "GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD"
@@ -91,10 +92,10 @@ struct split_commit_graph_opts {
  * is not compatible with the commit-graph feature, then the
  * methods will return 0 without writing a commit-graph.
  */
-int write_commit_graph_reachable(const char *obj_dir,
+int write_commit_graph_reachable(struct object_directory *odb,
 				 enum commit_graph_write_flags flags,
 				 const struct split_commit_graph_opts *split_opts);
-int write_commit_graph(const char *obj_dir,
+int write_commit_graph(struct object_directory *odb,
 		       struct string_list *pack_indexes,
 		       struct string_list *commit_hex,
 		       enum commit_graph_write_flags flags,
--
2.25.0.119.gaa12b7378b

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 2/5] commit-graph.h: store an odb in 'struct write_commit_graph_context'
  2020-02-04  5:51     ` Taylor Blau
@ 2020-02-04 19:54       ` Junio C Hamano
  2020-02-04 21:28         ` Taylor Blau
  0 siblings, 1 reply; 28+ messages in thread
From: Junio C Hamano @ 2020-02-04 19:54 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, peff, dstolee, martin.agren

Taylor Blau <me@ttaylorr.com> writes:

> Whoops. In v2, this patch introduces 'find_odb()' as a function in
> 'builtin/commit-graph.c', but does not declare it static. This causes
> breakage in gcc with '-Wmissing-prototypes'. Here is a correct version
> of the patch that does not cause such breakage.
>
> -- 8< --
>
> Subject: [PATCH v2 2/5] commit-graph.h: store an odb in 'struct

What happened to the rest of the line ;-)?

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 2/5] commit-graph.h: store an odb in 'struct write_commit_graph_context'
  2020-02-04 19:54       ` Junio C Hamano
@ 2020-02-04 21:28         ` Taylor Blau
  2020-02-04 21:44           ` Junio C Hamano
  0 siblings, 1 reply; 28+ messages in thread
From: Taylor Blau @ 2020-02-04 21:28 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Taylor Blau, git, peff, dstolee, martin.agren

On Tue, Feb 04, 2020 at 11:54:58AM -0800, Junio C Hamano wrote:
> Taylor Blau <me@ttaylorr.com> writes:
>
> > Whoops. In v2, this patch introduces 'find_odb()' as a function in
> > 'builtin/commit-graph.c', but does not declare it static. This causes
> > breakage in gcc with '-Wmissing-prototypes'. Here is a correct version
> > of the patch that does not cause such breakage.
> >
> > -- 8< --
> >
> > Subject: [PATCH v2 2/5] commit-graph.h: store an odb in 'struct
>
> What happened to the rest of the line ;-)?

Heh. Your email made me chuckle since this wasn't the first time I've
been asked about this today ;-). I manually yanked the 'Subject:' line,
but not the continuation below it.

I'd be happy to re-send a version of this patch to fix this, but if you
don't mind slicing it up, that works too.

Thanks,
Taylor

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 2/5] commit-graph.h: store an odb in 'struct write_commit_graph_context'
  2020-02-04 21:28         ` Taylor Blau
@ 2020-02-04 21:44           ` Junio C Hamano
  0 siblings, 0 replies; 28+ messages in thread
From: Junio C Hamano @ 2020-02-04 21:44 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, peff, dstolee, martin.agren

Taylor Blau <me@ttaylorr.com> writes:

> On Tue, Feb 04, 2020 at 11:54:58AM -0800, Junio C Hamano wrote:
>> Taylor Blau <me@ttaylorr.com> writes:
>>
>> > Whoops. In v2, this patch introduces 'find_odb()' as a function in
>> > 'builtin/commit-graph.c', but does not declare it static. This causes
>> > breakage in gcc with '-Wmissing-prototypes'. Here is a correct version
>> > of the patch that does not cause such breakage.
>> >
>> > -- 8< --
>> >
>> > Subject: [PATCH v2 2/5] commit-graph.h: store an odb in 'struct
>>
>> What happened to the rest of the line ;-)?
>
> Heh. Your email made me chuckle since this wasn't the first time I've
> been asked about this today ;-). I manually yanked the 'Subject:' line,
> but not the continuation below it.
>
> I'd be happy to re-send a version of this patch to fix this, but if you
> don't mind slicing it up, that works too.
>
> Thanks,
> Taylor

Noneedtoresend. Thanks.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 0/5] commit-graph: use 'struct object_directory *' everywhere
  2020-02-03 21:17 ` [PATCH v2 0/5] " Taylor Blau
                     ` (4 preceding siblings ...)
  2020-02-03 21:18   ` [PATCH v2 5/5] commit-graph.h: use odb in 'load_commit_graph_one_fd_st' Taylor Blau
@ 2020-02-05 12:30   ` Jeff King
  5 siblings, 0 replies; 28+ messages in thread
From: Jeff King @ 2020-02-05 12:30 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, dstolee, gitster, martin.agren

On Mon, Feb 03, 2020 at 01:17:53PM -0800, Taylor Blau wrote:

> Here is a re-roll of the series in this thread to replace string-based
> path comparison in 'commit-graph.c' code with raw pointer comparison of
> 'struct object_directory *'s.
> 
> The only thing that has changed substantially since v1 is that I swapped
> the order of patches 2/6 and 4/6. What was patch 3/6 got folded into
> what is now patch 2/5. This resolves an inconvenience where we had to
> define a helper function in 'commit-graph.c', when it really belonged in
> 'builtin/commit-graph.c'.
> 
> I took a few other suggestions from Martin in what is now patch 4/5, and
> noticed a few other small things along the way. A range-diff since v1 is
> included below.

Thanks, I read over this and the new layout looks quite good.

-Peff

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2020-02-05 12:30 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-30 23:00 [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Taylor Blau
2020-01-30 23:00 ` [PATCH 1/6] t5318: don't pass non-object directory to '--object-dir' Taylor Blau
2020-01-30 23:00 ` [PATCH 5/6] commit-graph.c: remove path normalization, comparison Taylor Blau
2020-01-30 23:00 ` [PATCH 6/6] commit-graph.h: use odb in 'load_commit_graph_one_fd_st' Taylor Blau
2020-01-30 23:00 ` [PATCH 2/6] commit-graph.h: store object directory in 'struct commit_graph' Taylor Blau
2020-01-31  6:52   ` Martin Ågren
2020-01-31 10:20     ` Jeff King
2020-01-31 19:19       ` Martin Ågren
2020-02-03  4:36       ` Taylor Blau
2020-02-03  8:36         ` Jeff King
2020-01-31 20:49     ` Junio C Hamano
2020-02-03  3:58     ` Taylor Blau
2020-01-30 23:00 ` [PATCH 4/6] commit-graph.h: store an odb in 'struct write_commit_graph_context' Taylor Blau
2020-01-30 23:00 ` [PATCH 3/6] builtin/commit-graph.c: die() with unknown '--object-dir' Taylor Blau
2020-01-31 10:30 ` [PATCH 0/6] commit-graph: use 'struct object_directory *' everywhere Jeff King
2020-01-31 13:22   ` Derrick Stolee
2020-02-03  4:38     ` Taylor Blau
2020-02-03 21:17 ` [PATCH v2 0/5] " Taylor Blau
2020-02-03 21:17   ` [PATCH v2 1/5] t5318: don't pass non-object directory to '--object-dir' Taylor Blau
2020-02-03 21:17   ` [PATCH v2 2/5] commit-graph.h: store an odb in 'struct write_commit_graph_context' Taylor Blau
2020-02-04  5:51     ` Taylor Blau
2020-02-04 19:54       ` Junio C Hamano
2020-02-04 21:28         ` Taylor Blau
2020-02-04 21:44           ` Junio C Hamano
2020-02-03 21:18   ` [PATCH v2 3/5] commit-graph.h: store object directory in 'struct commit_graph' Taylor Blau
2020-02-03 21:18   ` [PATCH v2 4/5] commit-graph.c: remove path normalization, comparison Taylor Blau
2020-02-03 21:18   ` [PATCH v2 5/5] commit-graph.h: use odb in 'load_commit_graph_one_fd_st' Taylor Blau
2020-02-05 12:30   ` [PATCH v2 0/5] commit-graph: use 'struct object_directory *' everywhere Jeff King

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).