midx.c: write MIDX filenames to strbuf

To ask for the name of a MIDX and its corresponding .rev file, callers invoke get_midx_filename() and get_midx_rev_filename(), respectively. These both invoke xstrfmt(), allocating a chunk of memory which must be freed later on. This makes callers in pack-bitmap.c somewhat awkward. Specifically, midx_bitmap_filename(), which is implemented like: return xstrfmt("%s-%s.bitmap", get_midx_filename(midx->object_dir), hash_to_hex(get_midx_checksum(midx))); this leaks the second argument to xstrfmt(), which itself was allocated with xstrfmt(). This caller could assign both the result of get_midx_filename() and the outer xstrfmt() to a temporary variable, remembering to free() the former before returning. But that involves a wasteful copy. Instead, get_midx_filename() and get_midx_rev_filename() take a strbuf as an output parameter. This way midx_bitmap_filename() can manipulate and pass around a temporary buffer which it detaches back to its caller. That allows us to implement the function without copying or open-coding get_midx_filename() in a way that doesn't leak. Update the other callers of get_midx_filename() and get_midx_rev_filename() accordingly. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed Oct 26, 2021 at 17:01 UTC 60980aed786487e9113f0cb2907dfc75a77d363c
4 files changed +49 -37
midx.c
+33 -26
@@ -57,15 +57,15 @@ const unsigned char *get_midx_checksum(struct multi_pack_index *m)
57 return m->data + m->data_len - the_hash_algo->rawsz;
58 }
59
60 -char *get_midx_filename(const char *object_dir)
60 +void get_midx_filename(struct strbuf *out, const char *object_dir)
61 {
62 - return xstrfmt("%s/pack/multi-pack-index", object_dir);
62 + strbuf_addf(out, "%s/pack/multi-pack-index", object_dir);
63 }
64
65 -char *get_midx_rev_filename(struct multi_pack_index *m)
65 +void get_midx_rev_filename(struct strbuf *out, struct multi_pack_index *m)
66 {
67 - return xstrfmt("%s/pack/multi-pack-index-%s.rev",
68 - m->object_dir, hash_to_hex(get_midx_checksum(m)));
67 + get_midx_filename(out, m->object_dir);
68 + strbuf_addf(out, "-%s.rev", hash_to_hex(get_midx_checksum(m)));
69 }
70
71 static int midx_read_oid_fanout(const unsigned char *chunk_start,
@@ -89,28 +89,30 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
89 size_t midx_size;
90 void *midx_map = NULL;
91 uint32_t hash_version;
92 - char *midx_name = get_midx_filename(object_dir);
92 + struct strbuf midx_name = STRBUF_INIT;
93 uint32_t i;
94 const char *cur_pack_name;
95 struct chunkfile *cf = NULL;
96
97 - fd = git_open(midx_name);
97 + get_midx_filename(&midx_name, object_dir);
98 +
99 + fd = git_open(midx_name.buf);
100
101 if (fd < 0)
102 goto cleanup_fail;
103 if (fstat(fd, &st)) {
102 - error_errno(_("failed to read %s"), midx_name);
104 + error_errno(_("failed to read %s"), midx_name.buf);
105 goto cleanup_fail;
106 }
107
108 midx_size = xsize_t(st.st_size);
109
110 if (midx_size < MIDX_MIN_SIZE) {
109 - error(_("multi-pack-index file %s is too small"), midx_name);
111 + error(_("multi-pack-index file %s is too small"), midx_name.buf);
112 goto cleanup_fail;
113 }
114
113 - FREE_AND_NULL(midx_name);
115 + strbuf_release(&midx_name);
116
117 midx_map = xmmap(NULL, midx_size, PROT_READ, MAP_PRIVATE, fd, 0);
118 close(fd);
@@ -184,7 +186,7 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
186
187 cleanup_fail:
188 free(m);
187 - free(midx_name);
189 + strbuf_release(&midx_name);
190 free_chunkfile(cf);
191 if (midx_map)
192 munmap(midx_map, midx_size);
@@ -1115,7 +1117,7 @@ static int write_midx_internal(const char *object_dir,
1117 const char *refs_snapshot,
1118 unsigned flags)
1119 {
1118 - char *midx_name;
1120 + struct strbuf midx_name = STRBUF_INIT;
1121 unsigned char midx_hash[GIT_MAX_RAWSZ];
1122 uint32_t i;
1123 struct hashfile *f = NULL;
@@ -1130,10 +1132,10 @@ static int write_midx_internal(const char *object_dir,
1132 /* Ensure the given object_dir is local, or a known alternate. */
1133 find_odb(the_repository, object_dir);
1134
1133 - midx_name = get_midx_filename(object_dir);
1134 - if (safe_create_leading_directories(midx_name))
1135 + get_midx_filename(&midx_name, object_dir);
1136 + if (safe_create_leading_directories(midx_name.buf))
1137 die_errno(_("unable to create leading directories of %s"),
1136 - midx_name);
1138 + midx_name.buf);
1139
1140 if (!packs_to_include) {
1141 /*
@@ -1367,7 +1369,7 @@ static int write_midx_internal(const char *object_dir,
1369 pack_name_concat_len += MIDX_CHUNK_ALIGNMENT -
1370 (pack_name_concat_len % MIDX_CHUNK_ALIGNMENT);
1371
1370 - hold_lock_file_for_update(&lk, midx_name, LOCK_DIE_ON_ERROR);
1372 + hold_lock_file_for_update(&lk, midx_name.buf, LOCK_DIE_ON_ERROR);
1373 f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
1374
1375 if (ctx.nr - dropped_packs == 0) {
@@ -1404,9 +1406,9 @@ static int write_midx_internal(const char *object_dir,
1406 ctx.pack_order = midx_pack_order(&ctx);
1407
1408 if (flags & MIDX_WRITE_REV_INDEX)
1407 - write_midx_reverse_index(midx_name, midx_hash, &ctx);
1409 + write_midx_reverse_index(midx_name.buf, midx_hash, &ctx);
1410 if (flags & MIDX_WRITE_BITMAP) {
1409 - if (write_midx_bitmap(midx_name, midx_hash, &ctx,
1411 + if (write_midx_bitmap(midx_name.buf, midx_hash, &ctx,
1412 refs_snapshot, flags) < 0) {
1413 error(_("could not write multi-pack bitmap"));
1414 result = 1;
@@ -1435,7 +1437,7 @@ cleanup:
1437 free(ctx.entries);
1438 free(ctx.pack_perm);
1439 free(ctx.pack_order);
1438 - free(midx_name);
1440 + strbuf_release(&midx_name);
1441
1442 return result;
1443 }
@@ -1499,20 +1501,22 @@ static void clear_midx_files_ext(const char *object_dir, const char *ext,
1501
1502 void clear_midx_file(struct repository *r)
1503 {
1502 - char *midx = get_midx_filename(r->objects->odb->path);
1504 + struct strbuf midx = STRBUF_INIT;
1505 +
1506 + get_midx_filename(&midx, r->objects->odb->path);
1507
1508 if (r->objects && r->objects->multi_pack_index) {
1509 close_midx(r->objects->multi_pack_index);
1510 r->objects->multi_pack_index = NULL;
1511 }
1512
1509 - if (remove_path(midx))
1510 - die(_("failed to clear multi-pack-index at %s"), midx);
1513 + if (remove_path(midx.buf))
1514 + die(_("failed to clear multi-pack-index at %s"), midx.buf);
1515
1516 clear_midx_files_ext(r->objects->odb->path, ".bitmap", NULL);
1517 clear_midx_files_ext(r->objects->odb->path, ".rev", NULL);
1518
1515 - free(midx);
1519 + strbuf_release(&midx);
1520 }
1521
1522 static int verify_midx_error;
@@ -1565,12 +1569,15 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
1569 if (!m) {
1570 int result = 0;
1571 struct stat sb;
1568 - char *filename = get_midx_filename(object_dir);
1569 - if (!stat(filename, &sb)) {
1572 + struct strbuf filename = STRBUF_INIT;
1573 +
1574 + get_midx_filename(&filename, object_dir);
1575 +
1576 + if (!stat(filename.buf, &sb)) {
1577 error(_("multi-pack-index file exists, but failed to parse"));
1578 result = 1;
1579 }
1573 - free(filename);
1580 + strbuf_release(&filename);
1581 return result;
1582 }
1583
midx.h
+2 -2
@@ -48,8 +48,8 @@ struct multi_pack_index {
48 #define MIDX_WRITE_BITMAP_HASH_CACHE (1 << 3)
49
50 const unsigned char *get_midx_checksum(struct multi_pack_index *m);
51 -char *get_midx_filename(const char *object_dir);
52 -char *get_midx_rev_filename(struct multi_pack_index *m);
51 +void get_midx_filename(struct strbuf *out, const char *object_dir);
52 +void get_midx_rev_filename(struct strbuf *out, struct multi_pack_index *m);
53
54 struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local);
55 int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id);
pack-bitmap.c
+10 -5
@@ -292,9 +292,12 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
292
293 char *midx_bitmap_filename(struct multi_pack_index *midx)
294 {
295 - return xstrfmt("%s-%s.bitmap",
296 - get_midx_filename(midx->object_dir),
297 - hash_to_hex(get_midx_checksum(midx)));
295 + struct strbuf buf = STRBUF_INIT;
296 +
297 + get_midx_filename(&buf, midx->object_dir);
298 + strbuf_addf(&buf, "-%s.bitmap", hash_to_hex(get_midx_checksum(midx)));
299 +
300 + return strbuf_detach(&buf, NULL);
301 }
302
303 char *pack_bitmap_filename(struct packed_git *p)
@@ -324,10 +327,12 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
327 }
328
329 if (bitmap_git->pack || bitmap_git->midx) {
330 + struct strbuf buf = STRBUF_INIT;
331 + get_midx_filename(&buf, midx->object_dir);
332 /* ignore extra bitmap file; we can only handle one */
328 - warning("ignoring extra bitmap file: %s",
329 - get_midx_filename(midx->object_dir));
333 + warning("ignoring extra bitmap file: %s", buf.buf);
334 close(fd);
335 + strbuf_release(&buf);
336 return -1;
337 }
338
pack-revindex.c
+4 -4
@@ -296,14 +296,14 @@ int load_pack_revindex(struct packed_git *p)
296
297 int load_midx_revindex(struct multi_pack_index *m)
298 {
299 - char *revindex_name;
299 + struct strbuf revindex_name = STRBUF_INIT;
300 int ret;
301 if (m->revindex_data)
302 return 0;
303
304 - revindex_name = get_midx_rev_filename(m);
304 + get_midx_rev_filename(&revindex_name, m);
305
306 - ret = load_revindex_from_disk(revindex_name,
306 + ret = load_revindex_from_disk(revindex_name.buf,
307 m->num_objects,
308 &m->revindex_map,
309 &m->revindex_len);
@@ -313,7 +313,7 @@ int load_midx_revindex(struct multi_pack_index *m)
313 m->revindex_data = (const uint32_t *)((const char *)m->revindex_map + RIDX_HEADER_SIZE);
314
315 cleanup:
316 - free(revindex_name);
316 + strbuf_release(&revindex_name);
317 return ret;
318 }
319