When writing commit-graph files, we append path data to an
object directory, which may be specified by the user via the
'--object-dir' option. If the user supplies a trailing slash,
or some other alternative path format, the resulting path may
be usable for writing to the correct location. However, when
expiring graph files from the <obj-dir>/info/commit-graphs
directory during a write, we need to compare paths with exact
string matches.

Normalize the commit-graph filenames to avoid ambiguity. This
creates extra allocations, but this is a constant multiple of
the number of commit-graph files, which should be a number in
the single digits.

Further normalize the object directory in the context. Due to
a comparison between g->obj_dir and ctx->obj_dir in
split_graph_merge_strategy(), a trailing slash would prevent
any merging of layers within the same object directory. The
check is there to ensure we do not merge across alternates.
Update the tests to include a case with this trailing slash
problem.

Signed-off-by: Derrick Stolee <dsto...@microsoft.com>
---

Sorry for the previously-bad patch. This one I believe to
be a full correction, and also includes a test to ensure
we do not make this mistake again.

Thanks,
-Stolee

 commit-graph.c | 36 ++++++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/commit-graph.c b/commit-graph.c
index 8842f93910..2836a6fc3d 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -43,15 +43,23 @@
 
 char *get_commit_graph_filename(const char *obj_dir)
 {
-       return xstrfmt("%s/info/commit-graph", obj_dir);
+       char *filename = xstrfmt("%s/info/commit-graph", obj_dir);
+       char *normalized = xmalloc(strlen(filename) + 1);
+       normalize_path_copy(normalized, filename);
+       free(filename);
+       return normalized;
 }
 
 static char *get_split_graph_filename(const char *obj_dir,
                                      const char *oid_hex)
 {
-       return xstrfmt("%s/info/commit-graphs/graph-%s.graph",
-                      obj_dir,
-                      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;
 }
 
 static char *get_chain_filename(const char *obj_dir)
@@ -744,7 +752,7 @@ struct packed_oid_list {
 
 struct write_commit_graph_context {
        struct repository *r;
-       const char *obj_dir;
+       char *obj_dir;
        char *graph_name;
        struct packed_oid_list oids;
        struct packed_commit_list commits;
@@ -1693,7 +1701,11 @@ static void expire_commit_graphs(struct 
write_commit_graph_context *ctx)
        }
 
        strbuf_addstr(&path, ctx->obj_dir);
-       strbuf_addstr(&path, "/info/commit-graphs");
+
+       if (path.buf[path.len - 1] != '/')
+               strbuf_addch(&path, '/');
+
+       strbuf_addstr(&path, "info/commit-graphs");
        dir = opendir(path.buf);
 
        if (!dir) {
@@ -1727,7 +1739,6 @@ static void expire_commit_graphs(struct 
write_commit_graph_context *ctx)
 
                if (!found)
                        unlink(path.buf);
-
        }
 }
 
@@ -1739,6 +1750,7 @@ 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))
@@ -1746,7 +1758,14 @@ int write_commit_graph(const char *obj_dir,
 
        ctx = xcalloc(1, sizeof(struct write_commit_graph_context));
        ctx->r = the_repository;
-       ctx->obj_dir = obj_dir;
+
+       /* 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->append = flags & COMMIT_GRAPH_APPEND ? 1 : 0;
        ctx->report_progress = flags & COMMIT_GRAPH_PROGRESS ? 1 : 0;
        ctx->split = flags & COMMIT_GRAPH_SPLIT ? 1 : 0;
@@ -1854,6 +1873,7 @@ 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++) {
-- 
2.22.0.430.g4f3aec613b

Reply via email to