X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=upload-pack.c;h=9f82941f8b1e1cd65ebcd7675f7b7ba63c24acae;hb=af9a01e1c2f6a8814b817eb7f3d78814389a3212;hp=67994680f2f48e573f78c592c853422e6d8995cf;hpb=82527cf33e59308b86cf3defe9ae0f5c2367a012;p=git.git diff --git a/upload-pack.c b/upload-pack.c index 67994680f..9f82941f8 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -27,7 +27,8 @@ static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=n static unsigned long oldest_have; static int multi_ack, nr_our_refs; -static int use_thin_pack, use_ofs_delta, no_progress; +static int use_thin_pack, use_ofs_delta, use_include_tag; +static int no_progress; static struct object_array have_obj; static struct object_array want_obj; static unsigned int timeout; @@ -35,6 +36,7 @@ static unsigned int timeout; * otherwise maximum packet size (up to 65520 bytes). */ static int use_sideband; +static int debug_fd; static void reset_timeout(void) { @@ -129,9 +131,12 @@ static int do_rev_list(int fd, void *create_full_pack) } setup_revisions(0, NULL, &revs, NULL); } - prepare_revision_walk(&revs); + if (prepare_revision_walk(&revs)) + die("revision walk setup failed"); mark_edges_uninteresting(revs.commits, &revs, show_edge); traverse_commit_list(&revs, show_commit, show_object); + fflush(pack_pipe); + fclose(pack_pipe); return 0; } @@ -144,6 +149,7 @@ static void create_pack_file(void) char abort_msg[] = "aborting due to possible repository " "corruption on the remote side."; int buffered = -1; + ssize_t sz; const char *argv[10]; int arg = 0; @@ -159,6 +165,8 @@ static void create_pack_file(void) argv[arg++] = "--progress"; if (use_ofs_delta) argv[arg++] = "--delta-base-offset"; + if (use_include_tag) + argv[arg++] = "--include-tag"; argv[arg++] = NULL; memset(&pack_objects, 0, sizeof(pack_objects)); @@ -168,22 +176,15 @@ static void create_pack_file(void) pack_objects.git_cmd = 1; pack_objects.argv = argv; - if (start_command(&pack_objects)) { - /* daemon sets things up to ignore TERM */ - kill(rev_list.pid, SIGKILL); + if (start_command(&pack_objects)) die("git-upload-pack: unable to fork git-pack-objects"); - } /* We read from pack_objects.err to capture stderr output for * progress bar, and pack_objects.out to capture the pack data. */ while (1) { - const char *who; struct pollfd pfd[2]; - pid_t pid; - int status; - ssize_t sz; int pe, pu, pollsize; reset_timeout(); @@ -204,123 +205,91 @@ static void create_pack_file(void) 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(pack_objects.out, cp, - sizeof(data) - outsz); - if (0 < sz) - ; - else if (sz == 0) { - close(pack_objects.out); - pack_objects.out = -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(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 (!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 (rev_list.pid || pack_objects.pid) { - pid = waitpid(-1, &status, WNOHANG); - if (!pid) - continue; - who = ((pid == rev_list.pid) ? "git-rev-list" : - (pid == pack_objects.pid) ? "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++; } - if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) { - error("git-upload-pack: %s died with error.", - who); + sz = xread(pack_objects.out, cp, + sizeof(data) - outsz); + if (0 < sz) + ; + else if (sz == 0) { + close(pack_objects.out); + pack_objects.out = -1; + } + else goto fail; + sz += outsz; + if (1 < sz) { + buffered = data[sz-1] & 0xFF; + sz--; } - if (pid == rev_list.pid) - rev_list.pid = 0; - if (pid == pack_objects.pid) - pack_objects.pid = 0; - if (rev_list.pid || pack_objects.pid) - 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 (pack_objects.pid) - kill(pack_objects.pid, SIGKILL); - if (rev_list.pid) - kill(rev_list.pid, SIGKILL); send_client_data(3, abort_msg, sizeof(abort_msg)); die("git-upload-pack: %s", abort_msg); } @@ -430,7 +399,6 @@ static int get_common_commits(void) char hex[41], last_hex[41]; int len; - track_object_refs = 0; save_commit_buffer = 0; for(;;) { @@ -482,6 +450,8 @@ static void receive_needs(void) static char line[1000]; int len, depth = 0; + if (debug_fd) + write_in_full(debug_fd, "#S\n", 3); for (;;) { struct object *o; unsigned char sha1_buf[20]; @@ -489,6 +459,8 @@ static void receive_needs(void) reset_timeout(); if (!len) break; + if (debug_fd) + write_in_full(debug_fd, line, len); if (!prefixcmp(line, "shallow ")) { unsigned char sha1[20]; @@ -527,6 +499,8 @@ static void receive_needs(void) use_sideband = DEFAULT_PACKET_MAX; if (strstr(line+45, "no-progress")) no_progress = 1; + if (strstr(line+45, "include-tag")) + use_include_tag = 1; /* We have sent all our refs already, and the other end * should have chosen out of them; otherwise they are @@ -544,6 +518,8 @@ static void receive_needs(void) add_object_array(o, NULL, &want_obj); } } + if (debug_fd) + write_in_full(debug_fd, "#E\n", 3); if (depth == 0 && shallows.nr == 0) return; if (depth > 0) { @@ -571,7 +547,8 @@ static void receive_needs(void) /* make sure the real parents are parsed */ unregister_shallow(object->sha1); object->parsed = 0; - parse_commit((struct commit *)object); + if (parse_commit((struct commit *)object)) + die("invalid commit"); parents = ((struct commit *)object)->parents; while (parents) { add_object_array(&parents->item->object, @@ -595,7 +572,8 @@ static void receive_needs(void) static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { static const char *capabilities = "multi_ack thin-pack side-band" - " side-band-64k ofs-delta shallow no-progress"; + " side-band-64k ofs-delta shallow no-progress" + " include-tag"; struct object *o = parse_object(sha1); if (!o) @@ -613,7 +591,8 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo } if (o->type == OBJ_TAG) { o = deref_tag(o, refname, 0); - packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname); + if (o) + packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname); } return 0; } @@ -658,12 +637,17 @@ int main(int argc, char **argv) if (i != argc-1) usage(upload_pack_usage); + + setup_path(NULL); + dir = argv[i]; if (!enter_repo(dir, strict)) die("'%s': unable to chdir or not a git archive", dir); if (is_repository_shallow()) die("attempt to fetch/clone from a shallow repository"); + if (getenv("GIT_DEBUG_SEND_PACK")) + debug_fd = atoi(getenv("GIT_DEBUG_SEND_PACK")); upload_pack(); return 0; }