From 2d6dacec88dd8dddae75b4a60b7a1944ac278354 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 19 Jan 2007 13:03:09 +0100 Subject: [PATCH] Make upload-pack.c work under MinGW. The forked rev-list process is turned into a thread. This should be OK since the rest of upload-pack does not access the revision machinery. In order to avoid the poll() call that waits for two file descriptors, it was necessary to remove sideband support. Then only one file descriptor needs to be monitored, which can be done in a simple while loop. --- upload-pack.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/upload-pack.c b/upload-pack.c index ec0f0cbfbe..ace719ce1a 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -96,7 +96,7 @@ static void show_edge(struct commit *commit) fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1)); } -static void do_rev_list(int create_full_pack) +static void do_rev_list(void *create_full_pack) { int i; struct rev_info revs; @@ -130,10 +130,13 @@ static void do_rev_list(int create_full_pack) prepare_revision_walk(&revs); mark_edges_uninteresting(revs.commits, &revs, show_edge); traverse_commit_list(&revs, show_commit, show_object); + fflush(pack_pipe); + fclose(pack_pipe); } static void create_pack_file(void) { +#ifndef __MINGW32__ /* Pipes between rev-list to pack-objects, pack-objects to us * and pack-objects error stream for progress bar. */ @@ -339,6 +342,86 @@ static void create_pack_file(void) kill(pid_rev_list, SIGKILL); send_client_data(3, abort_msg, sizeof(abort_msg)); die("git-upload-pack: %s", abort_msg); +#else + /* Pipes between rev-list to pack-objects, pack-objects to us. */ + int lp_pipe[2], pu_pipe[2]; + pid_t pid_pack_objects; + int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr); + char data[8193]; + char abort_msg[] = "aborting due to possible repository " + "corruption on the remote side."; + int buffered = -1; + ssize_t sz; + char *cp; + const char* argv[] = { "pack-objects", "--stdout", "-q", + use_ofs_delta ? "--delta-base-offset" : NULL, + NULL }; + + if (pipe(lp_pipe) < 0) + die("git-upload-pack: unable to create pipe"); + pack_pipe = fdopen(lp_pipe[1], "w"); + if (_beginthread(do_rev_list, 0, create_full_pack ? &create_full_pack : NULL) < 0) + die("git-upload-pack: unable to run rev-list: %s", strerror(errno)); + + if (pipe(pu_pipe) < 0) + die("git-upload-pack: unable to create pipe"); + + pid_pack_objects = spawnv_git_cmd(argv, lp_pipe, pu_pipe); + if (pid_pack_objects < 0) + die("git-upload-pack: unable to run git-pack-objects"); + + /* We read from pu_pipe[0] to capture the pack data. */ + + while ((sz = xread(pu_pipe[0], data+1, sizeof(data)-1)) > 0) { + cp = data+1; + /* 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. + */ + if (0 <= buffered) { + *--cp = buffered; + sz++; + } + if (1 < sz) { + buffered = cp[sz-1] & 0xFF; + sz--; + } + else + buffered = -1; + sz = send_client_data(1, cp, sz); + if (sz < 0) + goto fail; + } + if (sz == 0) { + close(pu_pipe[0]); + pu_pipe[0] = -1; + } + else + goto fail; + + /* 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); + if (waitpid(pid_pack_objects, NULL, 0) < 0) + die("git-upload-pack: waiting for pack-objects: %s", + strerror(errno)); + return; + + fail: + kill(pid_pack_objects, SIGKILL); + send_client_data(3, abort_msg, sizeof(abort_msg)); + die("git-upload-pack: %s", abort_msg); +#endif } static int got_sha1(char *hex, unsigned char *sha1)