tree-walk: add a strbuf wrapper for make_traverse_path()

All but one of the callers of make_traverse_path() allocate a new heap buffer to store the path. Let's give them an easy way to write to a strbuf, which saves them from computing the length themselves (which is especially tricky when they want to add to the path). It will also make it easier for us to change the make_traverse_path() interface in a future patch to improve its bounds-checking. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Jul 31, 2019 at 00:38 UTC c43ab062598d0299ea6e0d115a6018189a7793bf
5 files changed +32 -17
Documentation/technical/api-tree-walking.txt
+4
@@ -138,6 +138,10 @@ same in the next callback invocation.
138 This utilizes the memory structure of a tree entry to avoid the
139 overhead of using a generic strlen().
140
141 +`strbuf_make_traverse_path`::
142 +
143 + Convenience wrapper to `make_traverse_path` into a strbuf.
144 +
145 Authors
146 -------
147
builtin/merge-tree.c
+3 -2
@@ -180,8 +180,9 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const stru
180
181 static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)
182 {
183 - char *path = xmallocz(traverse_path_len(info, tree_entry_len(n)));
184 - return make_traverse_path(path, info, n->path, n->pathlen);
183 + struct strbuf buf = STRBUF_INIT;
184 + strbuf_make_traverse_path(&buf, info, n->path, n->pathlen);
185 + return strbuf_detach(&buf, NULL);
186 }
187
188 static void resolve(const struct traverse_info *info, struct name_entry *ours, struct name_entry *result)
tree-walk.c
+15 -6
@@ -200,6 +200,17 @@ char *make_traverse_path(char *path, const struct traverse_info *info,
200 return path;
201 }
202
203 +void strbuf_make_traverse_path(struct strbuf *out,
204 + const struct traverse_info *info,
205 + const char *name, size_t namelen)
206 +{
207 + size_t len = traverse_path_len(info, namelen);
208 +
209 + strbuf_grow(out, len);
210 + make_traverse_path(out->buf + out->len, info, name, namelen);
211 + strbuf_setlen(out, out->len + len);
212 +}
213 +
214 struct tree_desc_skip {
215 struct tree_desc_skip *prev;
216 const void *ptr;
@@ -396,12 +407,10 @@ int traverse_trees(struct index_state *istate,
407 tx[i].d = t[i];
408
409 if (info->prev) {
399 - strbuf_grow(&base, info->pathlen);
400 - make_traverse_path(base.buf, info->prev, info->name,
401 - info->namelen);
402 - base.buf[info->pathlen-1] = '/';
403 - strbuf_setlen(&base, info->pathlen);
404 - traverse_path = xstrndup(base.buf, info->pathlen);
410 + strbuf_make_traverse_path(&base, info->prev,
411 + info->name, info->namelen);
412 + strbuf_addch(&base, '/');
413 + traverse_path = xstrndup(base.buf, base.len);
414 } else {
415 traverse_path = xstrndup(info->name, info->pathlen);
416 }
tree-walk.h
+3
@@ -72,6 +72,9 @@ struct traverse_info {
72 int get_tree_entry(const struct object_id *, const char *, struct object_id *, unsigned short *);
73 char *make_traverse_path(char *path, const struct traverse_info *info,
74 const char *name, size_t namelen);
75 +void strbuf_make_traverse_path(struct strbuf *out,
76 + const struct traverse_info *info,
77 + const char *name, size_t namelen);
78 void setup_traverse_info(struct traverse_info *info, const char *base);
79
80 static inline size_t traverse_path_len(const struct traverse_info *info,
unpack-trees.c
+7 -9
@@ -686,21 +686,19 @@ static int index_pos_by_traverse_info(struct name_entry *names,
686 struct traverse_info *info)
687 {
688 struct unpack_trees_options *o = info->data;
689 - size_t len = traverse_path_len(info, tree_entry_len(names));
690 - char *name = xmalloc(len + 1 /* slash */ + 1 /* NUL */);
689 + struct strbuf name = STRBUF_INIT;
690 int pos;
691
693 - make_traverse_path(name, info, names->path, names->pathlen);
694 - name[len++] = '/';
695 - name[len] = '\0';
696 - pos = index_name_pos(o->src_index, name, len);
692 + strbuf_make_traverse_path(&name, info, names->path, names->pathlen);
693 + strbuf_addch(&name, '/');
694 + pos = index_name_pos(o->src_index, name.buf, name.len);
695 if (pos >= 0)
696 BUG("This is a directory and should not exist in index");
697 pos = -pos - 1;
700 - if (!starts_with(o->src_index->cache[pos]->name, name) ||
701 - (pos > 0 && starts_with(o->src_index->cache[pos-1]->name, name)))
698 + if (!starts_with(o->src_index->cache[pos]->name, name.buf) ||
699 + (pos > 0 && starts_with(o->src_index->cache[pos-1]->name, name.buf)))
700 BUG("pos must point at the first entry in this directory");
703 - free(name);
701 + strbuf_release(&name);
702 return pos;
703 }
704