static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_state) { struct child_process proc = CHILD_PROCESS_INIT; struct async muxer; const char *argv[2]; int code; argv[0] = find_hook(hook_name); if (!argv[0]) return 0; argv[1] = NULL; proc.argv = argv; proc.in = -1; proc.stdout_to_stderr = 1; if (use_sideband) { memset(&muxer, 0, sizeof(muxer)); muxer.proc = copy_to_sideband; muxer.in = -1; code = start_async(&muxer); if (code) return code; proc.err = muxer.in; } prepare_push_cert_sha1(&proc); code = start_command(&proc); if (code) { if (use_sideband) finish_async(&muxer); return code; } sigchain_push(SIGPIPE, SIG_IGN); while (1) { const char *buf; size_t n; if (feed(feed_state, &buf, &n)) break; if (write_in_full(proc.in, buf, n) != n) break; } close(proc.in); if (use_sideband) finish_async(&muxer); sigchain_pop(SIGPIPE); return finish_command(&proc); }
static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_state) { struct child_process proc; struct async muxer; const char *argv[2]; int code; if (access(hook_name, X_OK) < 0) return 0; argv[0] = hook_name; argv[1] = NULL; memset(&proc, 0, sizeof(proc)); proc.argv = argv; proc.in = -1; proc.stdout_to_stderr = 1; if (use_sideband) { memset(&muxer, 0, sizeof(muxer)); muxer.proc = copy_to_sideband; muxer.in = -1; code = start_async(&muxer); if (code) return code; proc.err = muxer.in; } code = start_command(&proc); if (code) { if (use_sideband) finish_async(&muxer); return code; } while (1) { const char *buf; size_t n; if (feed(feed_state, &buf, &n)) break; if (write_in_full(proc.in, buf, n) != n) break; } close(proc.in); if (use_sideband) finish_async(&muxer); return finish_command(&proc); }
static void execute_commands(struct command *commands, const char *unpacker_error, struct shallow_info *si, const struct string_list *push_options) { struct check_connected_options opt = CHECK_CONNECTED_INIT; struct command *cmd; unsigned char sha1[20]; struct iterate_data data; struct async muxer; int err_fd = 0; if (unpacker_error) { for (cmd = commands; cmd; cmd = cmd->next) cmd->error_string = "unpacker error"; return; } if (use_sideband) { memset(&muxer, 0, sizeof(muxer)); muxer.proc = copy_to_sideband; muxer.in = -1; if (!start_async(&muxer)) err_fd = muxer.in; /* ...else, continue without relaying sideband */ } data.cmds = commands; data.si = si; opt.err_fd = err_fd; opt.progress = err_fd && !quiet; if (check_connected(iterate_receive_command_list, &data, &opt)) set_connectivity_errors(commands, si); if (use_sideband) finish_async(&muxer); reject_updates_to_hidden(commands); if (run_receive_hook(commands, "pre-receive", 0, push_options)) { for (cmd = commands; cmd; cmd = cmd->next) { if (!cmd->error_string) cmd->error_string = "pre-receive hook declined"; } return; } check_aliased_updates(commands); free(head_name_to_free); head_name = head_name_to_free = resolve_refdup("HEAD", 0, sha1, NULL); if (use_atomic) execute_commands_atomic(commands, si); else execute_commands_non_atomic(commands, si); if (shallow_update) warn_if_skipped_connectivity_check(commands, si); }
static struct ref *parse_git_refs(struct discovery *heads) { struct ref *list = NULL; struct async async; memset(&async, 0, sizeof(async)); async.proc = write_discovery; async.data = heads; async.out = -1; if (start_async(&async)) die("cannot start thread to parse advertised refs"); get_remote_heads(async.out, &list, 0, NULL, 0, NULL); close(async.out); if (finish_async(&async)) die("ref parsing thread failed"); return list; }
static const char *unpack_with_sideband(void) { struct async muxer; const char *ret; if (!use_sideband) return unpack(0); memset(&muxer, 0, sizeof(muxer)); muxer.proc = copy_to_sideband; muxer.in = -1; if (start_async(&muxer)) return NULL; ret = unpack(muxer.in); finish_async(&muxer); return ret; }
static const char *unpack_with_sideband(struct shallow_info *si) { struct async muxer; const char *ret; if (!use_sideband) return unpack(0, si); use_keepalive = KEEPALIVE_AFTER_NUL; memset(&muxer, 0, sizeof(muxer)); muxer.proc = copy_to_sideband; muxer.in = -1; if (start_async(&muxer)) return NULL; ret = unpack(muxer.in, si); finish_async(&muxer); return ret; }
static int get_pack(struct fetch_pack_args *args, int xd[2], char **pack_lockfile) { struct async demux; const char *argv[22]; char keep_arg[256]; char hdr_arg[256]; const char **av, *cmd_name; int do_keep = args->keep_pack; struct child_process cmd; int ret; memset(&demux, 0, sizeof(demux)); if (use_sideband) { /* xd[] is talking with upload-pack; subprocess reads from * xd[0], spits out band#2 to stderr, and feeds us band#1 * through demux->out. */ demux.proc = sideband_demux; demux.data = xd; demux.out = -1; if (start_async(&demux)) die("fetch-pack: unable to fork off sideband" " demultiplexer"); } else demux.out = xd[0]; memset(&cmd, 0, sizeof(cmd)); cmd.argv = argv; av = argv; *hdr_arg = 0; if (!args->keep_pack && unpack_limit) { struct pack_header header; if (read_pack_header(demux.out, &header)) die("protocol error: bad pack header"); snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%"PRIu32",%"PRIu32, ntohl(header.hdr_version), ntohl(header.hdr_entries)); if (ntohl(header.hdr_entries) < unpack_limit) do_keep = 0; else do_keep = 1; } if (alternate_shallow_file) { *av++ = "--shallow-file"; *av++ = alternate_shallow_file; } if (do_keep) { if (pack_lockfile) cmd.out = -1; *av++ = cmd_name = "index-pack"; *av++ = "--stdin"; if (!args->quiet && !args->no_progress) *av++ = "-v"; if (args->use_thin_pack) *av++ = "--fix-thin"; if (args->lock_pack || unpack_limit) { int s = sprintf(keep_arg, "--keep=fetch-pack %"PRIuMAX " on ", (uintmax_t) getpid()); if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) strcpy(keep_arg + s, "localhost"); *av++ = keep_arg; } if (args->check_self_contained_and_connected) *av++ = "--check-self-contained-and-connected"; } else { *av++ = cmd_name = "unpack-objects"; if (args->quiet || args->no_progress) *av++ = "-q"; args->check_self_contained_and_connected = 0; } if (*hdr_arg) *av++ = hdr_arg; if (fetch_fsck_objects >= 0 ? fetch_fsck_objects : transfer_fsck_objects >= 0 ? transfer_fsck_objects : 0) *av++ = "--strict"; *av++ = NULL; cmd.in = demux.out; cmd.git_cmd = 1; if (start_command(&cmd)) die("fetch-pack: unable to fork off %s", cmd_name); if (do_keep && pack_lockfile) { *pack_lockfile = index_pack_lockfile(cmd.out); close(cmd.out); } if (!use_sideband) /* Closed by start_command() */ xd[0] = -1; ret = finish_command(&cmd); if (!ret || (args->check_self_contained_and_connected && ret == 1)) args->self_contained_and_connected = args->check_self_contained_and_connected && ret == 0; else die("%s failed", cmd_name); if (use_sideband && finish_async(&demux)) die("error in sideband demultiplexer"); return 0; }
int send_pack(struct send_pack_args *args, int fd[], struct child_process *conn, struct ref *remote_refs, struct extra_have_objects *extra_have) { int in = fd[0]; int out = fd[1]; struct strbuf req_buf = STRBUF_INIT; struct ref *ref; int new_refs; int allow_deleting_refs = 0; int status_report = 0; int use_sideband = 0; unsigned cmds_sent = 0; int ret; struct async demux; /* Does the other end support the reporting? */ if (server_supports("report-status")) status_report = 1; if (server_supports("delete-refs")) allow_deleting_refs = 1; if (server_supports("ofs-delta")) args->use_ofs_delta = 1; if (server_supports("side-band-64k")) use_sideband = 1; if (!remote_refs) { fprintf(stderr, "No refs in common and none specified; doing nothing.\n" "Perhaps you should specify a branch such as 'master'.\n"); return 0; } /* * Finally, tell the other end! */ new_refs = 0; for (ref = remote_refs; ref; ref = ref->next) { if (!ref->peer_ref && !args->send_mirror) continue; /* Check for statuses set by set_ref_status_for_push() */ switch (ref->status) { case REF_STATUS_REJECT_NONFASTFORWARD: case REF_STATUS_UPTODATE: continue; default: ; /* do nothing */ } if (ref->deletion && !allow_deleting_refs) { ref->status = REF_STATUS_REJECT_NODELETE; continue; } if (!ref->deletion) new_refs++; if (args->dry_run) { ref->status = REF_STATUS_OK; } else { char *old_hex = sha1_to_hex(ref->old_sha1); char *new_hex = sha1_to_hex(ref->new_sha1); if (!cmds_sent && (status_report || use_sideband)) { packet_buf_write(&req_buf, "%s %s %s%c%s%s", old_hex, new_hex, ref->name, 0, status_report ? " report-status" : "", use_sideband ? " side-band-64k" : ""); } else packet_buf_write(&req_buf, "%s %s %s", old_hex, new_hex, ref->name); ref->status = status_report ? REF_STATUS_EXPECTING_REPORT : REF_STATUS_OK; cmds_sent++; } } if (args->stateless_rpc) { if (!args->dry_run && cmds_sent) { packet_buf_flush(&req_buf); send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX); } } else { safe_write(out, req_buf.buf, req_buf.len); packet_flush(out); } strbuf_release(&req_buf); if (use_sideband && cmds_sent) { memset(&demux, 0, sizeof(demux)); demux.proc = sideband_demux; demux.data = fd; demux.out = -1; if (start_async(&demux)) die("send-pack: unable to fork off sideband demultiplexer"); in = demux.out; } if (new_refs && cmds_sent) { if (pack_objects(out, remote_refs, extra_have, args) < 0) { for (ref = remote_refs; ref; ref = ref->next) ref->status = REF_STATUS_NONE; if (args->stateless_rpc) close(out); if (git_connection_is_socket(conn)) shutdown(fd[0], SHUT_WR); if (use_sideband) finish_async(&demux); return -1; } } if (args->stateless_rpc && cmds_sent) packet_flush(out); if (status_report && cmds_sent) ret = receive_status(in, remote_refs); else ret = 0; if (args->stateless_rpc) packet_flush(out); if (use_sideband && cmds_sent) { if (finish_async(&demux)) { error("error in sideband demultiplexer"); ret = -1; } close(demux.out); } if (ret < 0) return ret; if (args->porcelain) return 0; for (ref = remote_refs; ref; ref = ref->next) { switch (ref->status) { case REF_STATUS_NONE: case REF_STATUS_UPTODATE: case REF_STATUS_OK: break; default: return -1; } } return 0; }
static int get_pack(struct fetch_pack_args *args, int xd[2], char **pack_lockfile) { struct async demux; int do_keep = args->keep_pack; const char *cmd_name; struct pack_header header; int pass_header = 0; struct child_process cmd = CHILD_PROCESS_INIT; int ret; memset(&demux, 0, sizeof(demux)); if (use_sideband) { /* xd[] is talking with upload-pack; subprocess reads from * xd[0], spits out band#2 to stderr, and feeds us band#1 * through demux->out. */ demux.proc = sideband_demux; demux.data = xd; demux.out = -1; demux.isolate_sigpipe = 1; if (start_async(&demux)) die(_("fetch-pack: unable to fork off sideband demultiplexer")); } else demux.out = xd[0]; if (!args->keep_pack && unpack_limit) { if (read_pack_header(demux.out, &header)) die(_("protocol error: bad pack header")); pass_header = 1; if (ntohl(header.hdr_entries) < unpack_limit) do_keep = 0; else do_keep = 1; } if (alternate_shallow_file) { argv_array_push(&cmd.args, "--shallow-file"); argv_array_push(&cmd.args, alternate_shallow_file); } if (do_keep || args->from_promisor) { if (pack_lockfile) cmd.out = -1; cmd_name = "index-pack"; argv_array_push(&cmd.args, cmd_name); argv_array_push(&cmd.args, "--stdin"); if (!args->quiet && !args->no_progress) argv_array_push(&cmd.args, "-v"); if (args->use_thin_pack) argv_array_push(&cmd.args, "--fix-thin"); if (do_keep && (args->lock_pack || unpack_limit)) { char hostname[HOST_NAME_MAX + 1]; if (xgethostname(hostname, sizeof(hostname))) xsnprintf(hostname, sizeof(hostname), "localhost"); argv_array_pushf(&cmd.args, "--keep=fetch-pack %"PRIuMAX " on %s", (uintmax_t)getpid(), hostname); } if (args->check_self_contained_and_connected) argv_array_push(&cmd.args, "--check-self-contained-and-connected"); if (args->from_promisor) argv_array_push(&cmd.args, "--promisor"); } else { cmd_name = "unpack-objects"; argv_array_push(&cmd.args, cmd_name); if (args->quiet || args->no_progress) argv_array_push(&cmd.args, "-q"); args->check_self_contained_and_connected = 0; } if (pass_header) argv_array_pushf(&cmd.args, "--pack_header=%"PRIu32",%"PRIu32, ntohl(header.hdr_version), ntohl(header.hdr_entries)); if (fetch_fsck_objects >= 0 ? fetch_fsck_objects : transfer_fsck_objects >= 0 ? transfer_fsck_objects : 0) { if (args->from_promisor) /* * We cannot use --strict in index-pack because it * checks both broken objects and links, but we only * want to check for broken objects. */ argv_array_push(&cmd.args, "--fsck-objects"); else argv_array_pushf(&cmd.args, "--strict%s", fsck_msg_types.buf); } cmd.in = demux.out; cmd.git_cmd = 1; if (start_command(&cmd)) die(_("fetch-pack: unable to fork off %s"), cmd_name); if (do_keep && pack_lockfile) { *pack_lockfile = index_pack_lockfile(cmd.out); close(cmd.out); } if (!use_sideband) /* Closed by start_command() */ xd[0] = -1; ret = finish_command(&cmd); if (!ret || (args->check_self_contained_and_connected && ret == 1)) args->self_contained_and_connected = args->check_self_contained_and_connected && ret == 0; else die(_("%s failed"), cmd_name); if (use_sideband && finish_async(&demux)) die(_("error in sideband demultiplexer")); return 0; }
static int run_and_feed_hook(const char *hook_name, feed_fn feed, struct receive_hook_feed_state *feed_state) { struct child_process proc = CHILD_PROCESS_INIT; struct async muxer; const char *argv[2]; int code; argv[0] = find_hook(hook_name); if (!argv[0]) return 0; argv[1] = NULL; proc.argv = argv; proc.in = -1; proc.stdout_to_stderr = 1; if (feed_state->push_options) { int i; for (i = 0; i < feed_state->push_options->nr; i++) argv_array_pushf(&proc.env_array, "GIT_PUSH_OPTION_%d=%s", i, feed_state->push_options->items[i].string); argv_array_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT=%d", feed_state->push_options->nr); } else argv_array_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT"); if (use_sideband) { memset(&muxer, 0, sizeof(muxer)); muxer.proc = copy_to_sideband; muxer.in = -1; code = start_async(&muxer); if (code) return code; proc.err = muxer.in; } prepare_push_cert_sha1(&proc); code = start_command(&proc); if (code) { if (use_sideband) finish_async(&muxer); return code; } sigchain_push(SIGPIPE, SIG_IGN); while (1) { const char *buf; size_t n; if (feed(feed_state, &buf, &n)) break; if (write_in_full(proc.in, buf, n) != n) break; } close(proc.in); if (use_sideband) finish_async(&muxer); sigchain_pop(SIGPIPE); return finish_command(&proc); }
int send_pack(struct send_pack_args *args, int fd[], struct child_process *conn, struct ref *remote_refs, struct sha1_array *extra_have) { int in = fd[0]; int out = fd[1]; struct strbuf req_buf = STRBUF_INIT; struct strbuf cap_buf = STRBUF_INIT; struct ref *ref; int need_pack_data = 0; int allow_deleting_refs = 0; int status_report = 0; int use_sideband = 0; int quiet_supported = 0; int agent_supported = 0; int use_atomic = 0; int atomic_supported = 0; int use_push_options = 0; int push_options_supported = 0; unsigned cmds_sent = 0; int ret; struct async demux; const char *push_cert_nonce = NULL; git_config(send_pack_config, NULL); /* Does the other end support the reporting? */ if (server_supports("report-status")) status_report = 1; if (server_supports("delete-refs")) allow_deleting_refs = 1; if (server_supports("ofs-delta")) args->use_ofs_delta = 1; if (config_use_sideband && server_supports("side-band-64k")) use_sideband = 1; if (server_supports("quiet")) quiet_supported = 1; if (server_supports("agent")) agent_supported = 1; if (server_supports("no-thin")) args->use_thin_pack = 0; if (server_supports("atomic")) atomic_supported = 1; if (server_supports("push-options")) push_options_supported = 1; if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) { int len; push_cert_nonce = server_feature_value("push-cert", &len); if (push_cert_nonce) { reject_invalid_nonce(push_cert_nonce, len); push_cert_nonce = xmemdupz(push_cert_nonce, len); } else if (args->push_cert == SEND_PACK_PUSH_CERT_ALWAYS) { die(_("the receiving end does not support --signed push")); } else if (args->push_cert == SEND_PACK_PUSH_CERT_IF_ASKED) { warning(_("not sending a push certificate since the" " receiving end does not support --signed" " push")); } } if (!remote_refs) { fprintf(stderr, "No refs in common and none specified; doing nothing.\n" "Perhaps you should specify a branch such as 'master'.\n"); return 0; } if (args->atomic && !atomic_supported) die(_("the receiving end does not support --atomic push")); use_atomic = atomic_supported && args->atomic; if (args->push_options && !push_options_supported) die(_("the receiving end does not support push options")); use_push_options = push_options_supported && args->push_options; if (status_report) strbuf_addstr(&cap_buf, " report-status"); if (use_sideband) strbuf_addstr(&cap_buf, " side-band-64k"); if (quiet_supported && (args->quiet || !args->progress)) strbuf_addstr(&cap_buf, " quiet"); if (use_atomic) strbuf_addstr(&cap_buf, " atomic"); if (use_push_options) strbuf_addstr(&cap_buf, " push-options"); if (agent_supported) strbuf_addf(&cap_buf, " agent=%s", git_user_agent_sanitized()); /* * NEEDSWORK: why does delete-refs have to be so specific to * send-pack machinery that set_ref_status_for_push() cannot * set this bit for us??? */ for (ref = remote_refs; ref; ref = ref->next) if (ref->deletion && !allow_deleting_refs) ref->status = REF_STATUS_REJECT_NODELETE; if (!args->dry_run) advertise_shallow_grafts_buf(&req_buf); if (!args->dry_run && push_cert_nonce) cmds_sent = generate_push_cert(&req_buf, remote_refs, args, cap_buf.buf, push_cert_nonce); /* * Clear the status for each ref and see if we need to send * the pack data. */ for (ref = remote_refs; ref; ref = ref->next) { switch (check_to_send_update(ref, args)) { case 0: /* no error */ break; case CHECK_REF_STATUS_REJECTED: /* * When we know the server would reject a ref update if * we were to send it and we're trying to send the refs * atomically, abort the whole operation. */ if (use_atomic) return atomic_push_failure(args, remote_refs, ref); /* Fallthrough for non atomic case. */ default: continue; } if (!ref->deletion) need_pack_data = 1; if (args->dry_run || !status_report) ref->status = REF_STATUS_OK; else ref->status = REF_STATUS_EXPECTING_REPORT; } /* * Finally, tell the other end! */ for (ref = remote_refs; ref; ref = ref->next) { char *old_hex, *new_hex; if (args->dry_run || push_cert_nonce) continue; if (check_to_send_update(ref, args) < 0) continue; old_hex = oid_to_hex(&ref->old_oid); new_hex = oid_to_hex(&ref->new_oid); if (!cmds_sent) { packet_buf_write(&req_buf, "%s %s %s%c%s", old_hex, new_hex, ref->name, 0, cap_buf.buf); cmds_sent = 1; } else { packet_buf_write(&req_buf, "%s %s %s", old_hex, new_hex, ref->name); } } if (args->stateless_rpc) { if (!args->dry_run && (cmds_sent || is_repository_shallow())) { packet_buf_flush(&req_buf); send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX); } } else { write_or_die(out, req_buf.buf, req_buf.len); packet_flush(out); } strbuf_release(&req_buf); strbuf_release(&cap_buf); if (use_push_options) { struct string_list_item *item; struct strbuf sb = STRBUF_INIT; for_each_string_list_item(item, args->push_options) packet_buf_write(&sb, "%s", item->string); write_or_die(out, sb.buf, sb.len); packet_flush(out); strbuf_release(&sb); } if (use_sideband && cmds_sent) { memset(&demux, 0, sizeof(demux)); demux.proc = sideband_demux; demux.data = fd; demux.out = -1; demux.isolate_sigpipe = 1; if (start_async(&demux)) die("send-pack: unable to fork off sideband demultiplexer"); in = demux.out; } if (need_pack_data && cmds_sent) { if (pack_objects(out, remote_refs, extra_have, args) < 0) { for (ref = remote_refs; ref; ref = ref->next) ref->status = REF_STATUS_NONE; if (args->stateless_rpc) close(out); if (git_connection_is_socket(conn)) shutdown(fd[0], SHUT_WR); if (use_sideband) { close(demux.out); finish_async(&demux); } fd[1] = -1; return -1; } if (!args->stateless_rpc) /* Closed by pack_objects() via start_command() */ fd[1] = -1; } if (args->stateless_rpc && cmds_sent) packet_flush(out); if (status_report && cmds_sent) ret = receive_status(in, remote_refs); else ret = 0; if (args->stateless_rpc) packet_flush(out); if (use_sideband && cmds_sent) { close(demux.out); if (finish_async(&demux)) { error("error in sideband demultiplexer"); ret = -1; } } if (ret < 0) return ret; if (args->porcelain) return 0; for (ref = remote_refs; ref; ref = ref->next) { switch (ref->status) { case REF_STATUS_NONE: case REF_STATUS_UPTODATE: case REF_STATUS_OK: break; default: return -1; } } return 0; }
static int get_pack(int xd[2], char **pack_lockfile) { struct async demux; const char *argv[20]; char keep_arg[256]; char hdr_arg[256]; const char **av; int do_keep = args.keep_pack; struct child_process cmd; memset(&demux, 0, sizeof(demux)); if (use_sideband) { /* xd[] is talking with upload-pack; subprocess reads from * xd[0], spits out band#2 to stderr, and feeds us band#1 * through demux->out. */ demux.proc = sideband_demux; demux.data = xd; if (start_async(&demux)) die("fetch-pack: unable to fork off sideband" " demultiplexer"); } else demux.out = xd[0]; memset(&cmd, 0, sizeof(cmd)); cmd.argv = argv; av = argv; *hdr_arg = 0; if (!args.keep_pack && unpack_limit) { struct pack_header header; if (read_pack_header(demux.out, &header)) die("protocol error: bad pack header"); snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%"PRIu32",%"PRIu32, ntohl(header.hdr_version), ntohl(header.hdr_entries)); if (ntohl(header.hdr_entries) < unpack_limit) do_keep = 0; else do_keep = 1; } if (do_keep) { if (pack_lockfile) cmd.out = -1; *av++ = "index-pack"; *av++ = "--stdin"; if (!args.quiet && !args.no_progress) *av++ = "-v"; if (args.use_thin_pack) *av++ = "--fix-thin"; if (args.lock_pack || unpack_limit) { int s = sprintf(keep_arg, "--keep=fetch-pack %"PRIuMAX " on ", (uintmax_t) getpid()); if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) strcpy(keep_arg + s, "localhost"); *av++ = keep_arg; } } else { *av++ = "unpack-objects"; if (args.quiet) *av++ = "-q"; } if (*hdr_arg) *av++ = hdr_arg; *av++ = NULL; cmd.in = demux.out; cmd.git_cmd = 1; if (start_command(&cmd)) die("fetch-pack: unable to fork off %s", argv[0]); if (do_keep && pack_lockfile) { *pack_lockfile = index_pack_lockfile(cmd.out); close(cmd.out); } if (finish_command(&cmd)) die("%s failed", argv[0]); if (use_sideband && finish_async(&demux)) die("error in sideband demultiplexer"); return 0; }
static void create_pack_file(void) { 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; ssize_t sz; const char *argv[10]; int arg = 0; argv[arg++] = "pack-objects"; if (!shallow_nr) { argv[arg++] = "--revs"; if (create_full_pack) argv[arg++] = "--all"; else if (use_thin_pack) argv[arg++] = "--thin"; } argv[arg++] = "--stdout"; if (!no_progress) 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)); pack_objects.in = -1; 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 (shallow_nr) { memset(&rev_list, 0, sizeof(rev_list)); rev_list.proc = do_rev_list; rev_list.out = pack_objects.in; if (start_async(&rev_list)) die("git upload-pack: unable to fork git-rev-list"); } else { FILE *pipe_fd = xfdopen(pack_objects.in, "w"); if (!create_full_pack) { int i; for (i = 0; i < want_obj.nr; i++) fprintf(pipe_fd, "%s\n", sha1_to_hex(want_obj.objects[i].item->sha1)); fprintf(pipe_fd, "--not\n"); for (i = 0; i < have_obj.nr; i++) fprintf(pipe_fd, "%s\n", sha1_to_hex(have_obj.objects[i].item->sha1)); } fprintf(pipe_fd, "\n"); fflush(pipe_fd); fclose(pipe_fd); } /* We read from pack_objects.err to capture stderr output for * progress bar, and pack_objects.out to capture the pack data. */ while (1) { struct pollfd pfd[2]; int pe, pu, pollsize; reset_timeout(); pollsize = 0; pe = pu = -1; if (0 <= pack_objects.out) { pfd[pollsize].fd = pack_objects.out; pfd[pollsize].events = POLLIN; pu = pollsize; pollsize++; } if (0 <= pack_objects.err) { pfd[pollsize].fd = pack_objects.err; pfd[pollsize].events = POLLIN; pe = pollsize; pollsize++; } if (!pollsize) break; if (poll(pfd, pollsize, -1) < 0) { if (errno != EINTR) { error("poll failed, resuming: %s", strerror(errno)); sleep(1); } continue; } 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; /* give priority to status messages */ 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; } 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 (finish_command(&pack_objects)) { error("git upload-pack: git-pack-objects died with error."); goto fail; } if (shallow_nr && 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: send_client_data(3, abort_msg, sizeof(abort_msg)); die("git upload-pack: %s", abort_msg); }