static struct ref *do_fetch_pack(struct fetch_pack_args *args, int fd[2], const struct ref *orig_ref, struct ref **sought, int nr_sought, struct shallow_info *si, char **pack_lockfile) { struct ref *ref = copy_ref_list(orig_ref); unsigned char sha1[20]; const char *agent_feature; int agent_len; sort_ref_list(&ref, ref_compare_name); qsort(sought, nr_sought, sizeof(*sought), cmp_ref_by_name); if (is_repository_shallow() && !server_supports("shallow")) die("Server does not support shallow clients"); if (server_supports("multi_ack_detailed")) { if (args->verbose) fprintf(stderr, "Server supports multi_ack_detailed\n"); multi_ack = 2; if (server_supports("no-done")) { if (args->verbose) fprintf(stderr, "Server supports no-done\n"); if (args->stateless_rpc) no_done = 1; } } else if (server_supports("multi_ack")) { if (args->verbose) fprintf(stderr, "Server supports multi_ack\n"); multi_ack = 1; } if (server_supports("side-band-64k")) { if (args->verbose) fprintf(stderr, "Server supports side-band-64k\n"); use_sideband = 2; } else if (server_supports("side-band")) { if (args->verbose) fprintf(stderr, "Server supports side-band\n"); use_sideband = 1; } if (server_supports("allow-tip-sha1-in-want")) { if (args->verbose) fprintf(stderr, "Server supports allow-tip-sha1-in-want\n"); allow_tip_sha1_in_want = 1; } if (!server_supports("thin-pack")) args->use_thin_pack = 0; if (!server_supports("no-progress")) args->no_progress = 0; if (!server_supports("include-tag")) args->include_tag = 0; if (server_supports("ofs-delta")) { if (args->verbose) fprintf(stderr, "Server supports ofs-delta\n"); } else prefer_ofs_delta = 0; if ((agent_feature = server_feature_value("agent", &agent_len))) { agent_supported = 1; if (args->verbose && agent_len) fprintf(stderr, "Server version is %.*s\n", agent_len, agent_feature); } if (everything_local(args, &ref, sought, nr_sought)) { packet_flush(fd[1]); goto all_done; } if (find_common(args, fd, sha1, ref) < 0) if (!args->keep_pack) /* When cloning, it is not unusual to have * no common commit. */ warning("no common commits"); if (args->stateless_rpc) packet_flush(fd[1]); if (args->depth > 0) setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL); else if (si->nr_ours || si->nr_theirs) alternate_shallow_file = setup_temporary_shallow(si->shallow); else alternate_shallow_file = NULL; if (get_pack(args, fd, pack_lockfile)) die("git fetch-pack: fetch failed."); all_done: return ref; }
static void create_pack_file(void) { struct child_process pack_objects; 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[12]; int i, arg = 0; FILE *pipe_fd; char *shallow_file = NULL; if (shallow_nr) { shallow_file = setup_temporary_shallow(); argv[arg++] = "--shallow-file"; argv[arg++] = shallow_file; } argv[arg++] = "pack-objects"; argv[arg++] = "--revs"; 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"); pipe_fd = xfdopen(pack_objects.in, "w"); 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)); for (i = 0; i < extra_edge_obj.nr; i++) fprintf(pipe_fd, "%s\n", sha1_to_hex(extra_edge_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; int ret; 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; ret = poll(pfd, pollsize, 1000 * keepalive); if (ret < 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; } /* * We hit the keepalive timeout without saying anything; send * an empty message on the data sideband just to let the other * side know we're still working on it, but don't have any data * yet. * * If we don't have a sideband channel, there's no room in the * protocol to say anything, so those clients are just out of * luck. */ if (!ret && use_sideband) { static const char buf[] = "0005\1"; write_or_die(1, buf, 5); } } if (finish_command(&pack_objects)) { error("git upload-pack: git-pack-objects died with error."); goto fail; } if (shallow_file) { if (*shallow_file) unlink(shallow_file); free(shallow_file); } /* 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); }
static const char *unpack(int err_fd, struct shallow_info *si) { struct pack_header hdr; const char *hdr_err; int status; char hdr_arg[38]; struct child_process child = CHILD_PROCESS_INIT; int fsck_objects = (receive_fsck_objects >= 0 ? receive_fsck_objects : transfer_fsck_objects >= 0 ? transfer_fsck_objects : 0); hdr_err = parse_pack_header(&hdr); if (hdr_err) { if (err_fd > 0) close(err_fd); return hdr_err; } snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%"PRIu32",%"PRIu32, ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (si->nr_ours || si->nr_theirs) { alt_shallow_file = setup_temporary_shallow(si->shallow); argv_array_push(&child.args, "--shallow-file"); argv_array_push(&child.args, alt_shallow_file); } if (ntohl(hdr.hdr_entries) < unpack_limit) { argv_array_pushl(&child.args, "unpack-objects", hdr_arg, NULL); if (quiet) argv_array_push(&child.args, "-q"); if (fsck_objects) argv_array_pushf(&child.args, "--strict%s", fsck_msg_types.buf); child.no_stdout = 1; child.err = err_fd; child.git_cmd = 1; status = run_command(&child); if (status) return "unpack-objects abnormal exit"; } else { char hostname[256]; argv_array_pushl(&child.args, "index-pack", "--stdin", hdr_arg, NULL); if (gethostname(hostname, sizeof(hostname))) xsnprintf(hostname, sizeof(hostname), "localhost"); argv_array_pushf(&child.args, "--keep=receive-pack %"PRIuMAX" on %s", (uintmax_t)getpid(), hostname); if (!quiet && err_fd) argv_array_push(&child.args, "--show-resolving-progress"); if (use_sideband) argv_array_push(&child.args, "--report-end-of-input"); if (fsck_objects) argv_array_pushf(&child.args, "--strict%s", fsck_msg_types.buf); if (!reject_thin) argv_array_push(&child.args, "--fix-thin"); child.out = -1; child.err = err_fd; child.git_cmd = 1; status = start_command(&child); if (status) return "index-pack fork failed"; pack_lockfile = index_pack_lockfile(child.out); close(child.out); status = finish_command(&child); if (status) return "index-pack abnormal exit"; reprepare_packed_git(); } return NULL; }
static struct ref *do_fetch_pack(struct fetch_pack_args *args, int fd[2], const struct ref *orig_ref, struct ref **sought, int nr_sought, struct shallow_info *si, char **pack_lockfile) { struct ref *ref = copy_ref_list(orig_ref); struct object_id oid; const char *agent_feature; int agent_len; struct fetch_negotiator negotiator; fetch_negotiator_init(&negotiator, negotiation_algorithm); sort_ref_list(&ref, ref_compare_name); QSORT(sought, nr_sought, cmp_ref_by_name); if ((args->depth > 0 || is_repository_shallow(the_repository)) && !server_supports("shallow")) die(_("Server does not support shallow clients")); if (args->depth > 0 || args->deepen_since || args->deepen_not) args->deepen = 1; if (server_supports("multi_ack_detailed")) { print_verbose(args, _("Server supports multi_ack_detailed")); multi_ack = 2; if (server_supports("no-done")) { print_verbose(args, _("Server supports no-done")); if (args->stateless_rpc) no_done = 1; } } else if (server_supports("multi_ack")) { print_verbose(args, _("Server supports multi_ack")); multi_ack = 1; } if (server_supports("side-band-64k")) { print_verbose(args, _("Server supports side-band-64k")); use_sideband = 2; } else if (server_supports("side-band")) { print_verbose(args, _("Server supports side-band")); use_sideband = 1; } if (server_supports("allow-tip-sha1-in-want")) { print_verbose(args, _("Server supports allow-tip-sha1-in-want")); allow_unadvertised_object_request |= ALLOW_TIP_SHA1; } if (server_supports("allow-reachable-sha1-in-want")) { print_verbose(args, _("Server supports allow-reachable-sha1-in-want")); allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1; } if (!server_supports("thin-pack")) args->use_thin_pack = 0; if (!server_supports("no-progress")) args->no_progress = 0; if (!server_supports("include-tag")) args->include_tag = 0; if (server_supports("ofs-delta")) print_verbose(args, _("Server supports ofs-delta")); else prefer_ofs_delta = 0; if (server_supports("filter")) { server_supports_filtering = 1; print_verbose(args, _("Server supports filter")); } else if (args->filter_options.choice) { warning("filtering not recognized by server, ignoring"); } if ((agent_feature = server_feature_value("agent", &agent_len))) { agent_supported = 1; if (agent_len) print_verbose(args, _("Server version is %.*s"), agent_len, agent_feature); } if (server_supports("deepen-since")) deepen_since_ok = 1; else if (args->deepen_since) die(_("Server does not support --shallow-since")); if (server_supports("deepen-not")) deepen_not_ok = 1; else if (args->deepen_not) die(_("Server does not support --shallow-exclude")); if (!server_supports("deepen-relative") && args->deepen_relative) die(_("Server does not support --deepen")); if (!args->no_dependents) { mark_complete_and_common_ref(&negotiator, args, &ref); filter_refs(args, &ref, sought, nr_sought); if (everything_local(args, &ref)) { packet_flush(fd[1]); goto all_done; } } else { filter_refs(args, &ref, sought, nr_sought); } if (find_common(&negotiator, args, fd, &oid, ref) < 0) if (!args->keep_pack) /* When cloning, it is not unusual to have * no common commit. */ warning(_("no common commits")); if (args->stateless_rpc) packet_flush(fd[1]); if (args->deepen) setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL); else if (si->nr_ours || si->nr_theirs) alternate_shallow_file = setup_temporary_shallow(si->shallow); else alternate_shallow_file = NULL; if (get_pack(args, fd, pack_lockfile)) die(_("git fetch-pack: fetch failed.")); all_done: negotiator.release(&negotiator); return ref; }
static const char *unpack(int err_fd, struct shallow_info *si) { struct pack_header hdr; struct argv_array av = ARGV_ARRAY_INIT; const char *hdr_err; int status; char hdr_arg[38]; struct child_process child; int fsck_objects = (receive_fsck_objects >= 0 ? receive_fsck_objects : transfer_fsck_objects >= 0 ? transfer_fsck_objects : 0); hdr_err = parse_pack_header(&hdr); if (hdr_err) { if (err_fd > 0) close(err_fd); return hdr_err; } snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%"PRIu32",%"PRIu32, ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (si->nr_ours || si->nr_theirs) { alt_shallow_file = setup_temporary_shallow(si->shallow); argv_array_pushl(&av, "--shallow-file", alt_shallow_file, NULL); } memset(&child, 0, sizeof(child)); if (ntohl(hdr.hdr_entries) < unpack_limit) { argv_array_pushl(&av, "unpack-objects", hdr_arg, NULL); if (quiet) argv_array_push(&av, "-q"); if (fsck_objects) argv_array_push(&av, "--strict"); child.argv = av.argv; child.no_stdout = 1; child.err = err_fd; child.git_cmd = 1; status = run_command(&child); if (status) return "unpack-objects abnormal exit"; } else { int s; char keep_arg[256]; s = sprintf(keep_arg, "--keep=receive-pack %"PRIuMAX" on ", (uintmax_t) getpid()); if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) strcpy(keep_arg + s, "localhost"); argv_array_pushl(&av, "index-pack", "--stdin", hdr_arg, keep_arg, NULL); if (fsck_objects) argv_array_push(&av, "--strict"); if (fix_thin) argv_array_push(&av, "--fix-thin"); child.argv = av.argv; child.out = -1; child.err = err_fd; child.git_cmd = 1; status = start_command(&child); if (status) return "index-pack fork failed"; pack_lockfile = index_pack_lockfile(child.out); close(child.out); status = finish_command(&child); if (status) return "index-pack abnormal exit"; reprepare_packed_git(); } return NULL; }