Merge branch 'ab/bundle-updates'
Code clean-up and leak plugging in "git bundle". * ab/bundle-updates: bundle: remove "ref_list" in favor of string-list.c API bundle.c: use a temporary variable for OIDs and names bundle cmd: stop leaking memory from parse_options_cmd_bundle()
This commit is contained in:
commit
cdeabf513a
@ -46,7 +46,7 @@ static int parse_options_cmd_bundle(int argc,
|
||||
const char* prefix,
|
||||
const char * const usagestr[],
|
||||
const struct option options[],
|
||||
const char **bundle_file) {
|
||||
char **bundle_file) {
|
||||
int newargc;
|
||||
newargc = parse_options(argc, argv, NULL, options, usagestr,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
@ -61,7 +61,7 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
|
||||
int progress = isatty(STDERR_FILENO);
|
||||
struct strvec pack_opts;
|
||||
int version = -1;
|
||||
|
||||
int ret;
|
||||
struct option options[] = {
|
||||
OPT_SET_INT('q', "quiet", &progress,
|
||||
N_("do not show progress meter"), 0),
|
||||
@ -76,7 +76,7 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
|
||||
N_("specify bundle format version")),
|
||||
OPT_END()
|
||||
};
|
||||
const char* bundle_file;
|
||||
char *bundle_file;
|
||||
|
||||
argc = parse_options_cmd_bundle(argc, argv, prefix,
|
||||
builtin_bundle_create_usage, options, &bundle_file);
|
||||
@ -94,75 +94,95 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
|
||||
|
||||
if (!startup_info->have_repository)
|
||||
die(_("Need a repository to create a bundle."));
|
||||
return !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);
|
||||
ret = !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);
|
||||
free(bundle_file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
struct option options[] = {
|
||||
OPT_BOOL('q', "quiet", &quiet,
|
||||
N_("do not show bundle details")),
|
||||
OPT_END()
|
||||
};
|
||||
const char* bundle_file;
|
||||
char *bundle_file;
|
||||
|
||||
argc = parse_options_cmd_bundle(argc, argv, 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)
|
||||
return 1;
|
||||
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
close(bundle_fd);
|
||||
if (verify_bundle(the_repository, &header, !quiet))
|
||||
return 1;
|
||||
if (verify_bundle(the_repository, &header, !quiet)) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fprintf(stderr, _("%s is okay\n"), bundle_file);
|
||||
return 0;
|
||||
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[] = {
|
||||
OPT_END()
|
||||
};
|
||||
const char* bundle_file;
|
||||
char *bundle_file;
|
||||
|
||||
argc = parse_options_cmd_bundle(argc, argv, 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)
|
||||
return 1;
|
||||
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
close(bundle_fd);
|
||||
return !!list_bundle_refs(&header, argc, argv);
|
||||
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[] = {
|
||||
OPT_END()
|
||||
};
|
||||
const char* bundle_file;
|
||||
char *bundle_file;
|
||||
|
||||
argc = parse_options_cmd_bundle(argc, argv, 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)
|
||||
return 1;
|
||||
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (!startup_info->have_repository)
|
||||
die(_("Need a repository to unbundle."));
|
||||
return !!unbundle(the_repository, &header, bundle_fd, 0) ||
|
||||
ret = !!unbundle(the_repository, &header, bundle_fd, 0) ||
|
||||
list_bundle_refs(&header, argc, argv);
|
||||
bundle_header_release(&header);
|
||||
cleanup:
|
||||
free(bundle_file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_bundle(int argc, const char **argv, const char *prefix)
|
||||
|
64
bundle.c
64
bundle.c
@ -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,33 +143,38 @@ 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;
|
||||
|
||||
for (i = 0; i < r->nr; i++) {
|
||||
struct object_id *oid;
|
||||
const char *name;
|
||||
|
||||
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;
|
||||
}
|
||||
printf("%s %s\n", oid_to_hex(&r->list[i].oid),
|
||||
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;
|
||||
}
|
||||
@ -181,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;
|
||||
@ -193,16 +202,18 @@ 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;
|
||||
struct object *o = parse_object(r, &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;
|
||||
add_pending_object(&revs, o, e->name);
|
||||
add_pending_object(&revs, o, name);
|
||||
continue;
|
||||
}
|
||||
if (++ret == 1)
|
||||
error("%s", message);
|
||||
error("%s %s", oid_to_hex(&e->oid), e->name);
|
||||
error("%s %s", oid_to_hex(oid), name);
|
||||
}
|
||||
if (revs.pending.nr != p->nr)
|
||||
return ret;
|
||||
@ -218,26 +229,29 @@ int verify_bundle(struct repository *r,
|
||||
i--;
|
||||
|
||||
for (i = 0; i < p->nr; i++) {
|
||||
struct ref_list_entry *e = p->list + i;
|
||||
struct object *o = parse_object(r, &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)
|
||||
continue;
|
||||
if (++ret == 1)
|
||||
error("%s", message);
|
||||
error("%s %s", oid_to_hex(&e->oid), e->name);
|
||||
error("%s %s", oid_to_hex(oid), name);
|
||||
}
|
||||
|
||||
/* Clean up objects used, as they will be reused. */
|
||||
for (i = 0; i < p->nr; i++) {
|
||||
struct ref_list_entry *e = p->list + i;
|
||||
commit = lookup_commit_reference_gently(r, &e->oid, 1);
|
||||
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:",
|
||||
|
21
bundle.h
21
bundle.h
@ -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,
|
||||
|
10
transport.c
10
transport.c
@ -147,9 +147,11 @@ 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;
|
||||
struct ref *ref = alloc_ref(e->name);
|
||||
oidcpy(&ref->old_oid, &e->oid);
|
||||
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->util;
|
||||
oidcpy(&ref->old_oid, oid);
|
||||
ref->next = result;
|
||||
result = ref;
|
||||
}
|
||||
@ -175,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;
|
||||
}
|
||||
@ -1081,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;
|
||||
|
Loading…
Reference in New Issue
Block a user