X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=upload-pack.c;h=7e04311027176fc87c1de7dd619000d2a75d4eb9;hb=9fac800cae287256cea0512f5c5effae7a7aa784;hp=fe96ef15c43fa6e3f8f947f84ddce3c498e82859;hpb=0f2890acd999e63892d0b5b401e70bdaefe3ba51;p=git.git diff --git a/upload-pack.c b/upload-pack.c index fe96ef15c..7e0431102 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -9,6 +9,7 @@ #include "diff.h" #include "revision.h" #include "list-objects.h" +#include "run-command.h" static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] "; @@ -96,117 +97,87 @@ static void show_edge(struct commit *commit) fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1)); } +static int do_rev_list(int fd, void *create_full_pack) +{ + int i; + struct rev_info revs; + + pack_pipe = fdopen(fd, "w"); + if (create_full_pack) + use_thin_pack = 0; /* no point doing it */ + init_revisions(&revs, NULL); + revs.tag_objects = 1; + revs.tree_objects = 1; + revs.blob_objects = 1; + if (use_thin_pack) + revs.edge_hint = 1; + + if (create_full_pack) { + const char *args[] = {"rev-list", "--all", NULL}; + setup_revisions(2, args, &revs, NULL); + } else { + for (i = 0; i < want_obj.nr; i++) { + struct object *o = want_obj.objects[i].item; + /* why??? */ + o->flags &= ~UNINTERESTING; + add_pending_object(&revs, o, NULL); + } + for (i = 0; i < have_obj.nr; i++) { + struct object *o = have_obj.objects[i].item; + o->flags |= UNINTERESTING; + add_pending_object(&revs, o, NULL); + } + setup_revisions(0, NULL, &revs, NULL); + } + prepare_revision_walk(&revs); + mark_edges_uninteresting(revs.commits, &revs, show_edge); + traverse_commit_list(&revs, show_commit, show_object); + return 0; +} + static void create_pack_file(void) { - /* Pipes between rev-list to pack-objects, pack-objects to us - * and pack-objects error stream for progress bar. - */ - int lp_pipe[2], pu_pipe[2], pe_pipe[2]; - pid_t pid_rev_list, pid_pack_objects; + struct async rev_list; + struct child_process pack_objects; int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr); char data[8193], progress[128]; char abort_msg[] = "aborting due to possible repository " "corruption on the remote side."; int buffered = -1; - - if (pipe(lp_pipe) < 0) - die("git-upload-pack: unable to create pipe"); - pid_rev_list = fork(); - if (pid_rev_list < 0) + ssize_t sz; + const char *argv[10]; + int arg = 0; + + rev_list.proc = do_rev_list; + /* .data is just a boolean: any non-NULL value will do */ + rev_list.data = create_full_pack ? &rev_list : NULL; + if (start_async(&rev_list)) die("git-upload-pack: unable to fork git-rev-list"); - if (!pid_rev_list) { - int i; - struct rev_info revs; - - close(lp_pipe[0]); - pack_pipe = fdopen(lp_pipe[1], "w"); - - if (create_full_pack) - use_thin_pack = 0; /* no point doing it */ - init_revisions(&revs, NULL); - revs.tag_objects = 1; - revs.tree_objects = 1; - revs.blob_objects = 1; - if (use_thin_pack) - revs.edge_hint = 1; - - if (create_full_pack) { - const char *args[] = {"rev-list", "--all", NULL}; - setup_revisions(2, args, &revs, NULL); - } else { - for (i = 0; i < want_obj.nr; i++) { - struct object *o = want_obj.objects[i].item; - /* why??? */ - o->flags &= ~UNINTERESTING; - add_pending_object(&revs, o, NULL); - } - for (i = 0; i < have_obj.nr; i++) { - struct object *o = have_obj.objects[i].item; - o->flags |= UNINTERESTING; - add_pending_object(&revs, o, NULL); - } - setup_revisions(0, NULL, &revs, NULL); - } - prepare_revision_walk(&revs); - mark_edges_uninteresting(revs.commits, &revs, show_edge); - traverse_commit_list(&revs, show_commit, show_object); - exit(0); - } - - if (pipe(pu_pipe) < 0) - die("git-upload-pack: unable to create pipe"); - if (pipe(pe_pipe) < 0) - die("git-upload-pack: unable to create pipe"); - pid_pack_objects = fork(); - if (pid_pack_objects < 0) { - /* daemon sets things up to ignore TERM */ - kill(pid_rev_list, SIGKILL); + argv[arg++] = "pack-objects"; + argv[arg++] = "--stdout"; + if (!no_progress) + argv[arg++] = "--progress"; + if (use_ofs_delta) + argv[arg++] = "--delta-base-offset"; + argv[arg++] = NULL; + + memset(&pack_objects, 0, sizeof(pack_objects)); + pack_objects.in = rev_list.out; /* start_command closes it */ + pack_objects.out = -1; + pack_objects.err = -1; + pack_objects.git_cmd = 1; + pack_objects.argv = argv; + + if (start_command(&pack_objects)) die("git-upload-pack: unable to fork git-pack-objects"); - } - if (!pid_pack_objects) { - const char *argv[10]; - int i = 0; - - dup2(lp_pipe[0], 0); - dup2(pu_pipe[1], 1); - dup2(pe_pipe[1], 2); - - close(lp_pipe[0]); - close(lp_pipe[1]); - close(pu_pipe[0]); - close(pu_pipe[1]); - close(pe_pipe[0]); - close(pe_pipe[1]); - - argv[i++] = "pack-objects"; - argv[i++] = "--stdout"; - if (!no_progress) - argv[i++] = "--progress"; - if (use_ofs_delta) - argv[i++] = "--delta-base-offset"; - argv[i++] = NULL; - - execv_git_cmd(argv); - kill(pid_rev_list, SIGKILL); - die("git-upload-pack: unable to exec git-pack-objects"); - } - close(lp_pipe[0]); - close(lp_pipe[1]); - - /* We read from pe_pipe[0] to capture stderr output for - * progress bar, and pu_pipe[0] to capture the pack data. + /* We read from pack_objects.err to capture stderr output for + * progress bar, and pack_objects.out to capture the pack data. */ - close(pe_pipe[1]); - close(pu_pipe[1]); while (1) { - const char *who; struct pollfd pfd[2]; - pid_t pid; - int status; - ssize_t sz; int pe, pu, pollsize; reset_timeout(); @@ -214,136 +185,104 @@ static void create_pack_file(void) pollsize = 0; pe = pu = -1; - if (0 <= pu_pipe[0]) { - pfd[pollsize].fd = pu_pipe[0]; + if (0 <= pack_objects.out) { + pfd[pollsize].fd = pack_objects.out; pfd[pollsize].events = POLLIN; pu = pollsize; pollsize++; } - if (0 <= pe_pipe[0]) { - pfd[pollsize].fd = pe_pipe[0]; + if (0 <= pack_objects.err) { + pfd[pollsize].fd = pack_objects.err; pfd[pollsize].events = POLLIN; pe = pollsize; pollsize++; } - if (pollsize) { - if (poll(pfd, pollsize, -1) < 0) { - if (errno != EINTR) { - error("poll failed, resuming: %s", - strerror(errno)); - sleep(1); - } - continue; - } - if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) { - /* Data ready; we keep the last byte - * to ourselves in case we detect - * broken rev-list, so that we can - * leave the stream corrupted. This - * is unfortunate -- unpack-objects - * would happily accept a valid pack - * data with trailing garbage, so - * appending garbage after we pass all - * the pack data is not good enough to - * signal breakage to downstream. - */ - char *cp = data; - ssize_t outsz = 0; - if (0 <= buffered) { - *cp++ = buffered; - outsz++; - } - sz = xread(pu_pipe[0], cp, - sizeof(data) - outsz); - if (0 < sz) - ; - else if (sz == 0) { - close(pu_pipe[0]); - pu_pipe[0] = -1; - } - else - goto fail; - sz += outsz; - if (1 < sz) { - buffered = data[sz-1] & 0xFF; - sz--; - } - else - buffered = -1; - sz = send_client_data(1, data, sz); - if (sz < 0) - goto fail; - } - if (0 <= pe && (pfd[pe].revents & (POLLIN|POLLHUP))) { - /* Status ready; we ship that in the side-band - * or dump to the standard error. - */ - sz = xread(pe_pipe[0], progress, - sizeof(progress)); - if (0 < sz) - send_client_data(2, progress, sz); - else if (sz == 0) { - close(pe_pipe[0]); - pe_pipe[0] = -1; - } - else - goto fail; + if (!pollsize) + break; + + if (poll(pfd, pollsize, -1) < 0) { + if (errno != EINTR) { + error("poll failed, resuming: %s", + strerror(errno)); + sleep(1); } + continue; } - - /* See if the children are still there */ - if (pid_rev_list || pid_pack_objects) { - pid = waitpid(-1, &status, WNOHANG); - if (!pid) - continue; - who = ((pid == pid_rev_list) ? "git-rev-list" : - (pid == pid_pack_objects) ? "git-pack-objects" : - NULL); - if (!who) { - if (pid < 0) { - error("git-upload-pack: %s", - strerror(errno)); - goto fail; - } - error("git-upload-pack: we weren't " - "waiting for %d", pid); - continue; + if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) { + /* Data ready; we keep the last byte to ourselves + * in case we detect broken rev-list, so that we + * can leave the stream corrupted. This is + * unfortunate -- unpack-objects would happily + * accept a valid packdata with trailing garbage, + * so appending garbage after we pass all the + * pack data is not good enough to signal + * breakage to downstream. + */ + char *cp = data; + ssize_t outsz = 0; + if (0 <= buffered) { + *cp++ = buffered; + outsz++; + } + sz = xread(pack_objects.out, cp, + sizeof(data) - outsz); + if (0 < sz) + ; + else if (sz == 0) { + close(pack_objects.out); + pack_objects.out = -1; } - if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) { - error("git-upload-pack: %s died with error.", - who); + else goto fail; + sz += outsz; + if (1 < sz) { + buffered = data[sz-1] & 0xFF; + sz--; } - if (pid == pid_rev_list) - pid_rev_list = 0; - if (pid == pid_pack_objects) - pid_pack_objects = 0; - if (pid_rev_list || pid_pack_objects) - continue; - } - - /* both died happily */ - if (pollsize) - continue; - - /* flush the data */ - if (0 <= buffered) { - data[0] = buffered; - sz = send_client_data(1, data, 1); + else + buffered = -1; + sz = send_client_data(1, data, sz); if (sz < 0) goto fail; - fprintf(stderr, "flushed.\n"); } - if (use_sideband) - packet_flush(1); - return; + if (0 <= pe && (pfd[pe].revents & (POLLIN|POLLHUP))) { + /* Status ready; we ship that in the side-band + * or dump to the standard error. + */ + sz = xread(pack_objects.err, progress, + sizeof(progress)); + if (0 < sz) + send_client_data(2, progress, sz); + else if (sz == 0) { + close(pack_objects.err); + pack_objects.err = -1; + } + else + goto fail; + } } + + if (finish_command(&pack_objects)) { + error("git-upload-pack: git-pack-objects died with error."); + goto fail; + } + if (finish_async(&rev_list)) + goto fail; /* error was already reported */ + + /* flush the data */ + if (0 <= buffered) { + data[0] = buffered; + sz = send_client_data(1, data, 1); + if (sz < 0) + goto fail; + fprintf(stderr, "flushed.\n"); + } + if (use_sideband) + packet_flush(1); + return; + fail: - if (pid_pack_objects) - kill(pid_pack_objects, SIGKILL); - if (pid_rev_list) - kill(pid_rev_list, SIGKILL); send_client_data(3, abort_msg, sizeof(abort_msg)); die("git-upload-pack: %s", abort_msg); }