From fb9a54150d308345a7027baae528b8fe90bd41f7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Feb 2007 21:25:41 +0100 Subject: [PATCH] git-bundle: avoid fork() in verify_bundle() We can use the revision walker easily for checking if the prerequisites are met, instead of fork()ing off a rev-list, which would list only the first unmet prerequisite. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-bundle.c | 75 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/builtin-bundle.c b/builtin-bundle.c index 521bbdad8b..191ec5570f 100644 --- a/builtin-bundle.c +++ b/builtin-bundle.c @@ -19,7 +19,7 @@ static const char bundle_signature[] = "# v2 git bundle\n"; struct ref_list { unsigned int nr, alloc; - struct { + struct ref_list_entry { unsigned char sha1[20]; char *name; } *list; @@ -167,33 +167,54 @@ static int verify_bundle(struct bundle_header *header) * to be verbose about the errors */ struct ref_list *p = &header->prerequisites; - char **argv; - int pid, out, i, ret = 0; - char buffer[1024]; + struct rev_info revs; + const char *argv[] = {NULL, "--all"}; + struct object_array refs; + struct commit *commit; + int i, ret = 0, req_nr; + const char *message = "The bundle requires these lacking revs:"; - argv = xmalloc((p->nr + 4) * sizeof(const char *)); - argv[0] = "rev-list"; - argv[1] = "--not"; - argv[2] = "--all"; - for (i = 0; i < p->nr; i++) - argv[i + 3] = xstrdup(sha1_to_hex(p->list[i].sha1)); - argv[p->nr + 3] = NULL; - out = -1; - pid = fork_with_pipe((const char **)argv, NULL, &out); - if (pid < 0) - return error("Could not fork rev-list"); - while (read_string(out, buffer, sizeof(buffer)) > 0) - ; /* do nothing */ - close(out); - for (i = 0; i < p->nr; i++) - free(argv[i + 3]); - free(argv); - - while (waitpid(pid, &i, 0) < 0) - if (errno != EINTR) - return -1; - if (!ret && (!WIFEXITED(i) || WEXITSTATUS(i))) - return error("At least one prerequisite is lacking."); + init_revisions(&revs, NULL); + for (i = 0; i < p->nr; i++) { + struct ref_list_entry *e = p->list + i; + struct object *o = parse_object(e->sha1); + if (o) { + o->flags |= BOUNDARY_SHOW; + add_pending_object(&revs, o, e->name); + continue; + } + if (++ret == 1) + error(message); + error("%s %s", sha1_to_hex(e->sha1), e->name); + } + if (revs.pending.nr == 0) + return ret; + req_nr = revs.pending.nr; + setup_revisions(2, argv, &revs, NULL); + + memset(&refs, 0, sizeof(struct object_array)); + for (i = 0; i < revs.pending.nr; i++) { + struct object_array_entry *e = revs.pending.objects + i; + add_object_array(e->item, e->name, &refs); + } + + prepare_revision_walk(&revs); + + i = req_nr; + while (i && (commit = get_revision(&revs))) + if (commit->object.flags & BOUNDARY_SHOW) + i--; + + for (i = 0; i < req_nr; i++) + if (!(refs.objects[i].item->flags & SHOWN)) { + if (++ret == 1) + error(message); + error("%s %s", sha1_to_hex(refs.objects[i].item->sha1), + refs.objects[i].name); + } + + for (i = 0; i < refs.nr; i++) + clear_commit_marks((struct commit *)refs.objects[i].item, -1); return ret; } -- 2.11.4.GIT