bundle: remove "ref_list" in favor of string-list.c API

Move away from the "struct ref_list" in bundle.c in favor of the
almost identical string-list.c API.

That API fits this use-case perfectly, but did not exist in its
current form when this code was added in 2e0afafebd (Add git-bundle:
move objects and references by archive, 2007-02-22), with hindsight we
could have used the path-list API, which later got renamed to
string-list. See 8fd2cb4069 (Extract helper bits from
c-merge-recursive work, 2006-07-25)

We need to change "name" to "string" and "oid" to "util" to make this
conversion, but other than that the APIs are pretty much identical for
what bundle.c made use of.

Let's also replace the memset(..,0,...) pattern with a more idiomatic
"INIT" macro, and finally add a *_release() function so to free the
allocated memory.

Before this the add_to_ref_list() would leak memory, now e.g. "bundle
list-heads" reports no memory leaks at all under valgrind.

In the bundle_header_init() function we're using a clever trick to
memcpy() what we'd get from the corresponding
BUNDLE_HEADER_INIT. There is a concurrent series to make use of that
pattern more generally, see [1].

1. https://lore.kernel.org/git/cover-0.5-00000000000-20210701T104855Z-avarab@gmail.com/

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Acked-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Ævar Arnfjörð Bjarmason 2021-07-02 11:57:32 +02:00 committed by Junio C Hamano
parent 15e7c7dca6
commit 10b635b773
4 changed files with 50 additions and 43 deletions

View File

@ -100,7 +100,7 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
}
static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
struct bundle_header header;
struct bundle_header header = BUNDLE_HEADER_INIT;
int bundle_fd = -1;
int quiet = 0;
int ret;
@ -115,7 +115,6 @@ static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
builtin_bundle_verify_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
memset(&header, 0, sizeof(header));
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
ret = 1;
goto cleanup;
@ -130,11 +129,12 @@ static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
ret = 0;
cleanup:
free(bundle_file);
bundle_header_release(&header);
return ret;
}
static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix) {
struct bundle_header header;
struct bundle_header header = BUNDLE_HEADER_INIT;
int bundle_fd = -1;
int ret;
struct option options[] = {
@ -146,7 +146,6 @@ static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix
builtin_bundle_list_heads_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
memset(&header, 0, sizeof(header));
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
ret = 1;
goto cleanup;
@ -155,11 +154,12 @@ static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix
ret = !!list_bundle_refs(&header, argc, argv);
cleanup:
free(bundle_file);
bundle_header_release(&header);
return ret;
}
static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix) {
struct bundle_header header;
struct bundle_header header = BUNDLE_HEADER_INIT;
int bundle_fd = -1;
int ret;
struct option options[] = {
@ -171,7 +171,6 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
builtin_bundle_unbundle_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
memset(&header, 0, sizeof(header));
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
ret = 1;
goto cleanup;
@ -180,6 +179,7 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
die(_("Need a repository to unbundle."));
ret = !!unbundle(the_repository, &header, bundle_fd, 0) ||
list_bundle_refs(&header, argc, argv);
bundle_header_release(&header);
cleanup:
free(bundle_file);
return ret;

View File

@ -23,13 +23,16 @@ static struct {
{ 3, v3_bundle_signature },
};
static void add_to_ref_list(const struct object_id *oid, const char *name,
struct ref_list *list)
void bundle_header_init(struct bundle_header *header)
{
ALLOC_GROW(list->list, list->nr + 1, list->alloc);
oidcpy(&list->list[list->nr].oid, oid);
list->list[list->nr].name = xstrdup(name);
list->nr++;
struct bundle_header blank = BUNDLE_HEADER_INIT;
memcpy(header, &blank, sizeof(*header));
}
void bundle_header_release(struct bundle_header *header)
{
string_list_clear(&header->prerequisites, 1);
string_list_clear(&header->references, 1);
}
static int parse_capability(struct bundle_header *header, const char *capability)
@ -112,10 +115,11 @@ static int parse_bundle_header(int fd, struct bundle_header *header,
status = -1;
break;
} else {
struct object_id *dup = oiddup(&oid);
if (is_prereq)
add_to_ref_list(&oid, "", &header->prerequisites);
string_list_append(&header->prerequisites, "")->util = dup;
else
add_to_ref_list(&oid, p + 1, &header->references);
string_list_append(&header->references, p + 1)->util = dup;
}
}
@ -139,19 +143,19 @@ int read_bundle_header(const char *path, struct bundle_header *header)
int is_bundle(const char *path, int quiet)
{
struct bundle_header header;
struct bundle_header header = BUNDLE_HEADER_INIT;
int fd = open(path, O_RDONLY);
if (fd < 0)
return 0;
memset(&header, 0, sizeof(header));
fd = parse_bundle_header(fd, &header, quiet ? NULL : path);
if (fd >= 0)
close(fd);
bundle_header_release(&header);
return (fd >= 0);
}
static int list_refs(struct ref_list *r, int argc, const char **argv)
static int list_refs(struct string_list *r, int argc, const char **argv)
{
int i;
@ -162,14 +166,14 @@ static int list_refs(struct ref_list *r, int argc, const char **argv)
if (argc > 1) {
int j;
for (j = 1; j < argc; j++)
if (!strcmp(r->list[i].name, argv[j]))
if (!strcmp(r->items[i].string, argv[j]))
break;
if (j == argc)
continue;
}
oid = &r->list[i].oid;
name = r->list[i].name;
oid = r->items[i].util;
name = r->items[i].string;
printf("%s %s\n", oid_to_hex(oid), name);
}
return 0;
@ -186,7 +190,7 @@ int verify_bundle(struct repository *r,
* Do fast check, then if any prereqs are missing then go line by line
* to be verbose about the errors
*/
struct ref_list *p = &header->prerequisites;
struct string_list *p = &header->prerequisites;
struct rev_info revs;
const char *argv[] = {NULL, "--all", NULL};
struct commit *commit;
@ -198,9 +202,9 @@ int verify_bundle(struct repository *r,
repo_init_revisions(r, &revs, NULL);
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
const char *name = e->name;
struct object_id *oid = &e->oid;
struct string_list_item *e = p->items + i;
const char *name = e->string;
struct object_id *oid = e->util;
struct object *o = parse_object(r, oid);
if (o) {
o->flags |= PREREQ_MARK;
@ -225,9 +229,9 @@ int verify_bundle(struct repository *r,
i--;
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
const char *name = e->name;
struct object_id *oid = &e->oid;
struct string_list_item *e = p->items + i;
const char *name = e->string;
const struct object_id *oid = e->util;
struct object *o = parse_object(r, oid);
assert(o); /* otherwise we'd have returned early */
if (o->flags & SHOWN)
@ -239,15 +243,15 @@ int verify_bundle(struct repository *r,
/* Clean up objects used, as they will be reused. */
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
struct object_id *oid = &e->oid;
struct string_list_item *e = p->items + i;
struct object_id *oid = e->util;
commit = lookup_commit_reference_gently(r, oid, 1);
if (commit)
clear_commit_marks(commit, ALL_REV_FLAGS);
}
if (verbose) {
struct ref_list *r;
struct string_list *r;
r = &header->references;
printf_ln(Q_("The bundle contains this ref:",

View File

@ -3,22 +3,23 @@
#include "strvec.h"
#include "cache.h"
struct ref_list {
unsigned int nr, alloc;
struct ref_list_entry {
struct object_id oid;
char *name;
} *list;
};
#include "string-list.h"
struct bundle_header {
unsigned version;
struct ref_list prerequisites;
struct ref_list references;
struct string_list prerequisites;
struct string_list references;
const struct git_hash_algo *hash_algo;
};
#define BUNDLE_HEADER_INIT \
{ \
.prerequisites = STRING_LIST_INIT_DUP, \
.references = STRING_LIST_INIT_DUP, \
}
void bundle_header_init(struct bundle_header *header);
void bundle_header_release(struct bundle_header *header);
int is_bundle(const char *path, int quiet);
int read_bundle_header(const char *path, struct bundle_header *header);
int create_bundle(struct repository *r, const char *path,

View File

@ -147,10 +147,10 @@ static struct ref *get_refs_from_bundle(struct transport *transport,
transport->hash_algo = data->header.hash_algo;
for (i = 0; i < data->header.references.nr; i++) {
struct ref_list_entry *e = data->header.references.list + i;
const char *name = e->name;
struct string_list_item *e = data->header.references.items + i;
const char *name = e->string;
struct ref *ref = alloc_ref(name);
struct object_id *oid = &e->oid;
struct object_id *oid = e->util;
oidcpy(&ref->old_oid, oid);
ref->next = result;
result = ref;
@ -177,6 +177,7 @@ static int close_bundle(struct transport *transport)
struct bundle_transport_data *data = transport->data;
if (data->fd > 0)
close(data->fd);
bundle_header_release(&data->header);
free(data);
return 0;
}
@ -1083,6 +1084,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
die(_("git-over-rsync is no longer supported"));
} else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) {
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
bundle_header_init(&data->header);
transport_check_allowed("file");
ret->data = data;
ret->vtable = &bundle_vtable;