static void receive_wanted_refs(struct packet_reader *reader, struct ref **sought, int nr_sought) { process_section_header(reader, "wanted-refs", 0); while (packet_reader_read(reader) == PACKET_READ_NORMAL) { struct object_id oid; const char *end; int i; if (parse_oid_hex(reader->line, &oid, &end) || *end++ != ' ') die(_("expected wanted-ref, got '%s'"), reader->line); for (i = 0; i < nr_sought; i++) { if (!strcmp(end, sought[i]->name)) { oidcpy(&sought[i]->old_oid, &oid); break; } } if (i == nr_sought) die(_("unexpected wanted-ref: '%s'"), reader->line); } if (reader->status != PACKET_READ_DELIM) die(_("error processing wanted refs: %d"), reader->status); }
static int process_acks(struct fetch_negotiator *negotiator, struct packet_reader *reader, struct oidset *common) { /* received */ int received_ready = 0; int received_ack = 0; process_section_header(reader, "acknowledgments", 0); while (packet_reader_read(reader) == PACKET_READ_NORMAL) { const char *arg; if (!strcmp(reader->line, "NAK")) continue; if (skip_prefix(reader->line, "ACK ", &arg)) { struct object_id oid; if (!get_oid_hex(arg, &oid)) { struct commit *commit; oidset_insert(common, &oid); commit = lookup_commit(the_repository, &oid); negotiator->ack(negotiator, commit); } continue; } if (!strcmp(reader->line, "ready")) { received_ready = 1; continue; } die(_("unexpected acknowledgment line: '%s'"), reader->line); } if (reader->status != PACKET_READ_FLUSH && reader->status != PACKET_READ_DELIM) die(_("error processing acks: %d"), reader->status); /* * If an "acknowledgments" section is sent, a packfile is sent if and * only if "ready" was sent in this section. The other sections * ("shallow-info" and "wanted-refs") are sent only if a packfile is * sent. Therefore, a DELIM is expected if "ready" is sent, and a FLUSH * otherwise. */ if (received_ready && reader->status != PACKET_READ_DELIM) die(_("expected packfile to be sent after 'ready'")); if (!received_ready && reader->status != PACKET_READ_FLUSH) die(_("expected no other sections to be sent after no 'ready'")); /* return 0 if no common, 1 if there are common, or 2 if ready */ return received_ready ? 2 : (received_ack ? 1 : 0); }
static void receive_shallow_info(struct fetch_pack_args *args, struct packet_reader *reader) { int line_received = 0; process_section_header(reader, "shallow-info", 0); while (packet_reader_read(reader) == PACKET_READ_NORMAL) { const char *arg; struct object_id oid; if (skip_prefix(reader->line, "shallow ", &arg)) { if (get_oid_hex(arg, &oid)) die(_("invalid shallow line: %s"), reader->line); register_shallow(the_repository, &oid); line_received = 1; continue; } if (skip_prefix(reader->line, "unshallow ", &arg)) { if (get_oid_hex(arg, &oid)) die(_("invalid unshallow line: %s"), reader->line); if (!lookup_object(the_repository, oid.hash)) die(_("object not found: %s"), reader->line); /* make sure that it is parsed as shallow */ if (!parse_object(the_repository, &oid)) die(_("error in object: %s"), reader->line); if (unregister_shallow(&oid)) die(_("no shallow found: %s"), reader->line); line_received = 1; continue; } die(_("expected shallow/unshallow, got %s"), reader->line); } if (reader->status != PACKET_READ_FLUSH && reader->status != PACKET_READ_DELIM) die(_("error processing shallow info: %d"), reader->status); if (line_received) { setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL); args->deepen = 1; } }
static int process_acks(struct fetch_negotiator *negotiator, struct packet_reader *reader, struct oidset *common) { /* received */ int received_ready = 0; int received_ack = 0; process_section_header(reader, "acknowledgments", 0); while (packet_reader_read(reader) == PACKET_READ_NORMAL) { const char *arg; if (!strcmp(reader->line, "NAK")) continue; if (skip_prefix(reader->line, "ACK ", &arg)) { struct object_id oid; if (!get_oid_hex(arg, &oid)) { struct commit *commit; oidset_insert(common, &oid); commit = lookup_commit(the_repository, &oid); negotiator->ack(negotiator, commit); } continue; } if (!strcmp(reader->line, "ready")) { received_ready = 1; continue; } die(_("unexpected acknowledgment line: '%s'"), reader->line); } if (reader->status != PACKET_READ_FLUSH && reader->status != PACKET_READ_DELIM) die(_("error processing acks: %d"), reader->status); /* return 0 if no common, 1 if there are common, or 2 if ready */ return received_ready ? 2 : (received_ack ? 1 : 0); }
static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, int fd[2], const struct ref *orig_ref, struct ref **sought, int nr_sought, char **pack_lockfile) { struct ref *ref = copy_ref_list(orig_ref); enum fetch_state state = FETCH_CHECK_LOCAL; struct oidset common = OIDSET_INIT; struct packet_reader reader; int in_vain = 0; int haves_to_send = INITIAL_FLUSH; struct fetch_negotiator negotiator; fetch_negotiator_init(&negotiator, negotiation_algorithm); packet_reader_init(&reader, fd[0], NULL, 0, PACKET_READ_CHOMP_NEWLINE); while (state != FETCH_DONE) { switch (state) { case FETCH_CHECK_LOCAL: sort_ref_list(&ref, ref_compare_name); QSORT(sought, nr_sought, cmp_ref_by_name); /* v2 supports these by default */ allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1; use_sideband = 2; if (args->depth > 0 || args->deepen_since || args->deepen_not) args->deepen = 1; /* Filter 'ref' by 'sought' and those that aren't local */ if (!args->no_dependents) { mark_complete_and_common_ref(&negotiator, args, &ref); filter_refs(args, &ref, sought, nr_sought); if (everything_local(args, &ref)) state = FETCH_DONE; else state = FETCH_SEND_REQUEST; mark_tips(&negotiator, args->negotiation_tips); for_each_cached_alternate(&negotiator, insert_one_alternate_object); } else { filter_refs(args, &ref, sought, nr_sought); state = FETCH_SEND_REQUEST; } break; case FETCH_SEND_REQUEST: if (send_fetch_request(&negotiator, fd[1], args, ref, &common, &haves_to_send, &in_vain)) state = FETCH_GET_PACK; else state = FETCH_PROCESS_ACKS; break; case FETCH_PROCESS_ACKS: /* Process ACKs/NAKs */ switch (process_acks(&negotiator, &reader, &common)) { case 2: state = FETCH_GET_PACK; break; case 1: in_vain = 0; /* fallthrough */ default: state = FETCH_SEND_REQUEST; break; } break; case FETCH_GET_PACK: /* Check for shallow-info section */ if (process_section_header(&reader, "shallow-info", 1)) receive_shallow_info(args, &reader); if (process_section_header(&reader, "wanted-refs", 1)) receive_wanted_refs(&reader, sought, nr_sought); /* get the pack */ process_section_header(&reader, "packfile", 0); if (get_pack(args, fd, pack_lockfile)) die(_("git fetch-pack: fetch failed.")); state = FETCH_DONE; break; case FETCH_DONE: continue; } } negotiator.release(&negotiator); oidset_clear(&common); return ref; }