git
/
upload-pack.c
1864 строки · 49.2 Кб
1#define USE_THE_REPOSITORY_VARIABLE2
3#include "git-compat-util.h"4#include "config.h"5#include "environment.h"6#include "gettext.h"7#include "hex.h"8#include "refs.h"9#include "pkt-line.h"10#include "sideband.h"11#include "repository.h"12#include "object-store-ll.h"13#include "oid-array.h"14#include "object.h"15#include "commit.h"16#include "diff.h"17#include "revision.h"18#include "list-objects-filter-options.h"19#include "run-command.h"20#include "connect.h"21#include "sigchain.h"22#include "version.h"23#include "string-list.h"24#include "strvec.h"25#include "trace2.h"26#include "protocol.h"27#include "upload-pack.h"28#include "commit-graph.h"29#include "commit-reach.h"30#include "shallow.h"31#include "write-or-die.h"32#include "json-writer.h"33#include "strmap.h"34
35/* Remember to update object flag allocation in object.h */
36#define THEY_HAVE (1u << 11)37#define OUR_REF (1u << 12)38#define WANTED (1u << 13)39#define COMMON_KNOWN (1u << 14)40
41#define SHALLOW (1u << 16)42#define NOT_SHALLOW (1u << 17)43#define CLIENT_SHALLOW (1u << 18)44#define HIDDEN_REF (1u << 19)45
46#define ALL_FLAGS (THEY_HAVE | OUR_REF | WANTED | COMMON_KNOWN | SHALLOW | \47NOT_SHALLOW | CLIENT_SHALLOW | HIDDEN_REF)48
49/* Enum for allowed unadvertised object request (UOR) */
50enum allow_uor {51/* Allow specifying sha1 if it is a ref tip. */52ALLOW_TIP_SHA1 = 0x01,53/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */54ALLOW_REACHABLE_SHA1 = 0x02,55/* Allow request of any sha1. Implies ALLOW_TIP_SHA1 and ALLOW_REACHABLE_SHA1. */56ALLOW_ANY_SHA1 = 0x0757};58
59/*
60* Please annotate, and if possible group together, fields used only
61* for protocol v0 or only for protocol v2.
62*/
63struct upload_pack_data {64struct string_list symref; /* v0 only */65struct object_array want_obj;66struct object_array have_obj;67struct strmap wanted_refs; /* v2 only */68struct strvec hidden_refs;69
70struct object_array shallows;71struct oidset deepen_not;72struct object_array extra_edge_obj;73int depth;74timestamp_t deepen_since;75int deepen_rev_list;76int deepen_relative;77int keepalive;78int shallow_nr;79timestamp_t oldest_have;80
81unsigned int timeout; /* v0 only */82enum {83NO_MULTI_ACK = 0,84MULTI_ACK = 1,85MULTI_ACK_DETAILED = 286} multi_ack; /* v0 only */87
88/* 0 for no sideband, otherwise DEFAULT_PACKET_MAX or LARGE_PACKET_MAX */89int use_sideband;90
91struct string_list uri_protocols;92enum allow_uor allow_uor;93
94struct list_objects_filter_options filter_options;95struct string_list allowed_filters;96
97struct packet_writer writer;98
99char *pack_objects_hook;100
101unsigned stateless_rpc : 1; /* v0 only */102unsigned no_done : 1; /* v0 only */103unsigned daemon_mode : 1; /* v0 only */104unsigned filter_capability_requested : 1; /* v0 only */105
106unsigned use_thin_pack : 1;107unsigned use_ofs_delta : 1;108unsigned no_progress : 1;109unsigned use_include_tag : 1;110unsigned wait_for_done : 1;111unsigned allow_filter : 1;112unsigned allow_filter_fallback : 1;113unsigned long tree_filter_max_depth;114
115unsigned done : 1; /* v2 only */116unsigned allow_ref_in_want : 1; /* v2 only */117unsigned allow_sideband_all : 1; /* v2 only */118unsigned seen_haves : 1; /* v2 only */119unsigned allow_packfile_uris : 1; /* v2 only */120unsigned advertise_sid : 1;121unsigned sent_capabilities : 1;122};123
124static void upload_pack_data_init(struct upload_pack_data *data)125{
126struct string_list symref = STRING_LIST_INIT_DUP;127struct strmap wanted_refs = STRMAP_INIT;128struct strvec hidden_refs = STRVEC_INIT;129struct object_array want_obj = OBJECT_ARRAY_INIT;130struct object_array have_obj = OBJECT_ARRAY_INIT;131struct object_array shallows = OBJECT_ARRAY_INIT;132struct oidset deepen_not = OID_ARRAY_INIT;133struct string_list uri_protocols = STRING_LIST_INIT_DUP;134struct object_array extra_edge_obj = OBJECT_ARRAY_INIT;135struct string_list allowed_filters = STRING_LIST_INIT_DUP;136
137memset(data, 0, sizeof(*data));138data->symref = symref;139data->wanted_refs = wanted_refs;140data->hidden_refs = hidden_refs;141data->want_obj = want_obj;142data->have_obj = have_obj;143data->shallows = shallows;144data->deepen_not = deepen_not;145data->uri_protocols = uri_protocols;146data->extra_edge_obj = extra_edge_obj;147data->allowed_filters = allowed_filters;148data->allow_filter_fallback = 1;149data->tree_filter_max_depth = ULONG_MAX;150packet_writer_init(&data->writer, 1);151list_objects_filter_init(&data->filter_options);152
153data->keepalive = 5;154data->advertise_sid = 0;155}
156
157static void upload_pack_data_clear(struct upload_pack_data *data)158{
159string_list_clear(&data->symref, 1);160strmap_clear(&data->wanted_refs, 1);161strvec_clear(&data->hidden_refs);162object_array_clear(&data->want_obj);163object_array_clear(&data->have_obj);164object_array_clear(&data->shallows);165oidset_clear(&data->deepen_not);166object_array_clear(&data->extra_edge_obj);167list_objects_filter_release(&data->filter_options);168string_list_clear(&data->allowed_filters, 0);169
170free((char *)data->pack_objects_hook);171}
172
173static void reset_timeout(unsigned int timeout)174{
175alarm(timeout);176}
177
178static void send_client_data(int fd, const char *data, ssize_t sz,179int use_sideband)180{
181if (use_sideband) {182send_sideband(1, fd, data, sz, use_sideband);183return;184}185if (fd == 3)186/* emergency quit */187fd = 2;188if (fd == 2) {189/* XXX: are we happy to lose stuff here? */190xwrite(fd, data, sz);191return;192}193write_or_die(fd, data, sz);194}
195
196static int write_one_shallow(const struct commit_graft *graft, void *cb_data)197{
198FILE *fp = cb_data;199if (graft->nr_parent == -1)200fprintf(fp, "--shallow %s\n", oid_to_hex(&graft->oid));201return 0;202}
203
204struct output_state {205/*206* We do writes no bigger than LARGE_PACKET_DATA_MAX - 1, because with
207* sideband-64k the band designator takes up 1 byte of space. Because
208* relay_pack_data keeps the last byte to itself, we make the buffer 1
209* byte bigger than the intended maximum write size.
210*/
211char buffer[(LARGE_PACKET_DATA_MAX - 1) + 1];212int used;213unsigned packfile_uris_started : 1;214unsigned packfile_started : 1;215};216
217static int relay_pack_data(int pack_objects_out, struct output_state *os,218int use_sideband, int write_packfile_line)219{
220/*221* We keep the last byte to ourselves
222* in case we detect broken rev-list, so that we
223* can leave the stream corrupted. This is
224* unfortunate -- unpack-objects would happily
225* accept a valid packdata with trailing garbage,
226* so appending garbage after we pass all the
227* pack data is not good enough to signal
228* breakage to downstream.
229*/
230ssize_t readsz;231
232readsz = xread(pack_objects_out, os->buffer + os->used,233sizeof(os->buffer) - os->used);234if (readsz < 0) {235return readsz;236}237os->used += readsz;238
239while (!os->packfile_started) {240char *p;241if (os->used >= 4 && !memcmp(os->buffer, "PACK", 4)) {242os->packfile_started = 1;243if (write_packfile_line) {244if (os->packfile_uris_started)245packet_delim(1);246packet_write_fmt(1, "\1packfile\n");247}248break;249}250if ((p = memchr(os->buffer, '\n', os->used))) {251if (!os->packfile_uris_started) {252os->packfile_uris_started = 1;253if (!write_packfile_line)254BUG("packfile_uris requires sideband-all");255packet_write_fmt(1, "\1packfile-uris\n");256}257*p = '\0';258packet_write_fmt(1, "\1%s\n", os->buffer);259
260os->used -= p - os->buffer + 1;261memmove(os->buffer, p + 1, os->used);262} else {263/*264* Incomplete line.
265*/
266return readsz;267}268}269
270if (os->used > 1) {271send_client_data(1, os->buffer, os->used - 1, use_sideband);272os->buffer[0] = os->buffer[os->used - 1];273os->used = 1;274} else {275send_client_data(1, os->buffer, os->used, use_sideband);276os->used = 0;277}278
279return readsz;280}
281
282static void create_pack_file(struct upload_pack_data *pack_data,283const struct string_list *uri_protocols)284{
285struct child_process pack_objects = CHILD_PROCESS_INIT;286struct output_state *output_state = xcalloc(1, sizeof(struct output_state));287char progress[128];288char abort_msg[] = "aborting due to possible repository "289"corruption on the remote side.";290ssize_t sz;291int i;292FILE *pipe_fd;293
294if (!pack_data->pack_objects_hook)295pack_objects.git_cmd = 1;296else {297strvec_push(&pack_objects.args, pack_data->pack_objects_hook);298strvec_push(&pack_objects.args, "git");299pack_objects.use_shell = 1;300}301
302if (pack_data->shallow_nr) {303strvec_push(&pack_objects.args, "--shallow-file");304strvec_push(&pack_objects.args, "");305}306strvec_push(&pack_objects.args, "pack-objects");307strvec_push(&pack_objects.args, "--revs");308if (pack_data->use_thin_pack)309strvec_push(&pack_objects.args, "--thin");310
311strvec_push(&pack_objects.args, "--stdout");312if (pack_data->shallow_nr)313strvec_push(&pack_objects.args, "--shallow");314if (!pack_data->no_progress)315strvec_push(&pack_objects.args, "--progress");316if (pack_data->use_ofs_delta)317strvec_push(&pack_objects.args, "--delta-base-offset");318if (pack_data->use_include_tag)319strvec_push(&pack_objects.args, "--include-tag");320if (pack_data->filter_options.choice) {321const char *spec =322expand_list_objects_filter_spec(&pack_data->filter_options);323strvec_pushf(&pack_objects.args, "--filter=%s", spec);324}325if (uri_protocols) {326for (i = 0; i < uri_protocols->nr; i++)327strvec_pushf(&pack_objects.args, "--uri-protocol=%s",328uri_protocols->items[i].string);329}330
331pack_objects.in = -1;332pack_objects.out = -1;333pack_objects.err = -1;334pack_objects.clean_on_exit = 1;335
336if (start_command(&pack_objects))337die("git upload-pack: unable to fork git-pack-objects");338
339pipe_fd = xfdopen(pack_objects.in, "w");340
341if (pack_data->shallow_nr)342for_each_commit_graft(write_one_shallow, pipe_fd);343
344for (i = 0; i < pack_data->want_obj.nr; i++)345fprintf(pipe_fd, "%s\n",346oid_to_hex(&pack_data->want_obj.objects[i].item->oid));347fprintf(pipe_fd, "--not\n");348for (i = 0; i < pack_data->have_obj.nr; i++)349fprintf(pipe_fd, "%s\n",350oid_to_hex(&pack_data->have_obj.objects[i].item->oid));351for (i = 0; i < pack_data->extra_edge_obj.nr; i++)352fprintf(pipe_fd, "%s\n",353oid_to_hex(&pack_data->extra_edge_obj.objects[i].item->oid));354fprintf(pipe_fd, "\n");355fflush(pipe_fd);356fclose(pipe_fd);357
358/* We read from pack_objects.err to capture stderr output for359* progress bar, and pack_objects.out to capture the pack data.
360*/
361
362while (1) {363struct pollfd pfd[2];364int pe, pu, pollsize, polltimeout;365int ret;366
367reset_timeout(pack_data->timeout);368
369pollsize = 0;370pe = pu = -1;371
372if (0 <= pack_objects.out) {373pfd[pollsize].fd = pack_objects.out;374pfd[pollsize].events = POLLIN;375pu = pollsize;376pollsize++;377}378if (0 <= pack_objects.err) {379pfd[pollsize].fd = pack_objects.err;380pfd[pollsize].events = POLLIN;381pe = pollsize;382pollsize++;383}384
385if (!pollsize)386break;387
388polltimeout = pack_data->keepalive < 0389? -1390: 1000 * pack_data->keepalive;391
392ret = poll(pfd, pollsize, polltimeout);393
394if (ret < 0) {395if (errno != EINTR) {396error_errno("poll failed, resuming");397sleep(1);398}399continue;400}401if (0 <= pe && (pfd[pe].revents & (POLLIN|POLLHUP))) {402/* Status ready; we ship that in the side-band403* or dump to the standard error.
404*/
405sz = xread(pack_objects.err, progress,406sizeof(progress));407if (0 < sz)408send_client_data(2, progress, sz,409pack_data->use_sideband);410else if (sz == 0) {411close(pack_objects.err);412pack_objects.err = -1;413}414else415goto fail;416/* give priority to status messages */417continue;418}419if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {420int result = relay_pack_data(pack_objects.out,421output_state,422pack_data->use_sideband,423!!uri_protocols);424
425if (result == 0) {426close(pack_objects.out);427pack_objects.out = -1;428} else if (result < 0) {429goto fail;430}431}432
433/*434* We hit the keepalive timeout without saying anything; send
435* an empty message on the data sideband just to let the other
436* side know we're still working on it, but don't have any data
437* yet.
438*
439* If we don't have a sideband channel, there's no room in the
440* protocol to say anything, so those clients are just out of
441* luck.
442*/
443if (!ret && pack_data->use_sideband) {444static const char buf[] = "0005\1";445write_or_die(1, buf, 5);446}447}448
449if (finish_command(&pack_objects)) {450error("git upload-pack: git-pack-objects died with error.");451goto fail;452}453
454/* flush the data */455if (output_state->used > 0) {456send_client_data(1, output_state->buffer, output_state->used,457pack_data->use_sideband);458fprintf(stderr, "flushed.\n");459}460free(output_state);461if (pack_data->use_sideband)462packet_flush(1);463return;464
465fail:466free(output_state);467send_client_data(3, abort_msg, strlen(abort_msg),468pack_data->use_sideband);469die("git upload-pack: %s", abort_msg);470}
471
472static int do_got_oid(struct upload_pack_data *data, const struct object_id *oid)473{
474int we_knew_they_have = 0;475struct object *o = parse_object_with_flags(the_repository, oid,476PARSE_OBJECT_SKIP_HASH_CHECK |477PARSE_OBJECT_DISCARD_TREE);478
479if (!o)480die("oops (%s)", oid_to_hex(oid));481if (o->type == OBJ_COMMIT) {482struct commit_list *parents;483struct commit *commit = (struct commit *)o;484if (o->flags & THEY_HAVE)485we_knew_they_have = 1;486else487o->flags |= THEY_HAVE;488if (!data->oldest_have || (commit->date < data->oldest_have))489data->oldest_have = commit->date;490for (parents = commit->parents;491parents;492parents = parents->next)493parents->item->object.flags |= THEY_HAVE;494}495if (!we_knew_they_have) {496add_object_array(o, NULL, &data->have_obj);497return 1;498}499return 0;500}
501
502static int got_oid(struct upload_pack_data *data,503const char *hex, struct object_id *oid)504{
505if (get_oid_hex(hex, oid))506die("git upload-pack: expected SHA1 object, got '%s'", hex);507if (!repo_has_object_file_with_flags(the_repository, oid,508OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))509return -1;510return do_got_oid(data, oid);511}
512
513static int ok_to_give_up(struct upload_pack_data *data)514{
515timestamp_t min_generation = GENERATION_NUMBER_ZERO;516
517if (!data->have_obj.nr)518return 0;519
520return can_all_from_reach_with_flag(&data->want_obj, THEY_HAVE,521COMMON_KNOWN, data->oldest_have,522min_generation);523}
524
525static int get_common_commits(struct upload_pack_data *data,526struct packet_reader *reader)527{
528struct object_id oid;529char last_hex[GIT_MAX_HEXSZ + 1];530int got_common = 0;531int got_other = 0;532int sent_ready = 0;533
534for (;;) {535const char *arg;536
537reset_timeout(data->timeout);538
539if (packet_reader_read(reader) != PACKET_READ_NORMAL) {540if (data->multi_ack == MULTI_ACK_DETAILED541&& got_common542&& !got_other543&& ok_to_give_up(data)) {544sent_ready = 1;545packet_write_fmt(1, "ACK %s ready\n", last_hex);546}547if (data->have_obj.nr == 0 || data->multi_ack)548packet_write_fmt(1, "NAK\n");549
550if (data->no_done && sent_ready) {551packet_write_fmt(1, "ACK %s\n", last_hex);552return 0;553}554if (data->stateless_rpc)555exit(0);556got_common = 0;557got_other = 0;558continue;559}560if (skip_prefix(reader->line, "have ", &arg)) {561switch (got_oid(data, arg, &oid)) {562case -1: /* they have what we do not */563got_other = 1;564if (data->multi_ack565&& ok_to_give_up(data)) {566const char *hex = oid_to_hex(&oid);567if (data->multi_ack == MULTI_ACK_DETAILED) {568sent_ready = 1;569packet_write_fmt(1, "ACK %s ready\n", hex);570} else571packet_write_fmt(1, "ACK %s continue\n", hex);572}573break;574default:575got_common = 1;576oid_to_hex_r(last_hex, &oid);577if (data->multi_ack == MULTI_ACK_DETAILED)578packet_write_fmt(1, "ACK %s common\n", last_hex);579else if (data->multi_ack)580packet_write_fmt(1, "ACK %s continue\n", last_hex);581else if (data->have_obj.nr == 1)582packet_write_fmt(1, "ACK %s\n", last_hex);583break;584}585continue;586}587if (!strcmp(reader->line, "done")) {588if (data->have_obj.nr > 0) {589if (data->multi_ack)590packet_write_fmt(1, "ACK %s\n", last_hex);591return 0;592}593packet_write_fmt(1, "NAK\n");594return -1;595}596die("git upload-pack: expected SHA1 list, got '%s'", reader->line);597}598}
599
600static int allow_hidden_refs(enum allow_uor allow_uor)601{
602if ((allow_uor & ALLOW_ANY_SHA1) == ALLOW_ANY_SHA1)603return 1;604return !(allow_uor & (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1));605}
606
607static void for_each_namespaced_ref_1(each_ref_fn fn,608struct upload_pack_data *data)609{
610const char **excludes = NULL;611/*612* If `data->allow_uor` allows fetching hidden refs, we need to
613* mark all references (including hidden ones), to check in
614* `is_our_ref()` below.
615*
616* Otherwise, we only care about whether each reference's object
617* has the OUR_REF bit set or not, so do not need to visit
618* hidden references.
619*/
620if (allow_hidden_refs(data->allow_uor))621excludes = hidden_refs_to_excludes(&data->hidden_refs);622
623refs_for_each_namespaced_ref(get_main_ref_store(the_repository),624excludes, fn, data);625}
626
627
628static int is_our_ref(struct object *o, enum allow_uor allow_uor)629{
630return o->flags & ((allow_hidden_refs(allow_uor) ? 0 : HIDDEN_REF) | OUR_REF);631}
632
633/*
634* on successful case, it's up to the caller to close cmd->out
635*/
636static int do_reachable_revlist(struct child_process *cmd,637struct object_array *src,638struct object_array *reachable,639enum allow_uor allow_uor)640{
641struct object *o;642FILE *cmd_in = NULL;643int i;644
645strvec_pushl(&cmd->args, "rev-list", "--stdin", NULL);646cmd->git_cmd = 1;647cmd->no_stderr = 1;648cmd->in = -1;649cmd->out = -1;650
651/*652* If the next rev-list --stdin encounters an unknown commit,
653* it terminates, which will cause SIGPIPE in the write loop
654* below.
655*/
656sigchain_push(SIGPIPE, SIG_IGN);657
658if (start_command(cmd))659goto error;660
661cmd_in = xfdopen(cmd->in, "w");662
663for (i = get_max_object_index(); 0 < i; ) {664o = get_indexed_object(--i);665if (!o)666continue;667if (reachable && o->type == OBJ_COMMIT)668o->flags &= ~TMP_MARK;669if (!is_our_ref(o, allow_uor))670continue;671if (fprintf(cmd_in, "^%s\n", oid_to_hex(&o->oid)) < 0)672goto error;673}674for (i = 0; i < src->nr; i++) {675o = src->objects[i].item;676if (is_our_ref(o, allow_uor)) {677if (reachable)678add_object_array(o, NULL, reachable);679continue;680}681if (reachable && o->type == OBJ_COMMIT)682o->flags |= TMP_MARK;683if (fprintf(cmd_in, "%s\n", oid_to_hex(&o->oid)) < 0)684goto error;685}686if (ferror(cmd_in) || fflush(cmd_in))687goto error;688fclose(cmd_in);689cmd->in = -1;690sigchain_pop(SIGPIPE);691
692return 0;693
694error:695sigchain_pop(SIGPIPE);696
697if (cmd_in)698fclose(cmd_in);699if (cmd->out >= 0)700close(cmd->out);701return -1;702}
703
704static int get_reachable_list(struct upload_pack_data *data,705struct object_array *reachable)706{
707struct child_process cmd = CHILD_PROCESS_INIT;708int i;709struct object *o;710char namebuf[GIT_MAX_HEXSZ + 2]; /* ^ + hash + LF */711const unsigned hexsz = the_hash_algo->hexsz;712
713if (do_reachable_revlist(&cmd, &data->shallows, reachable,714data->allow_uor) < 0)715return -1;716
717while ((i = read_in_full(cmd.out, namebuf, hexsz + 1)) == hexsz + 1) {718struct object_id oid;719const char *p;720
721if (parse_oid_hex(namebuf, &oid, &p) || *p != '\n')722break;723
724o = lookup_object(the_repository, &oid);725if (o && o->type == OBJ_COMMIT) {726o->flags &= ~TMP_MARK;727}728}729for (i = get_max_object_index(); 0 < i; i--) {730o = get_indexed_object(i - 1);731if (o && o->type == OBJ_COMMIT &&732(o->flags & TMP_MARK)) {733add_object_array(o, NULL, reachable);734o->flags &= ~TMP_MARK;735}736}737close(cmd.out);738
739if (finish_command(&cmd))740return -1;741
742return 0;743}
744
745static int has_unreachable(struct object_array *src, enum allow_uor allow_uor)746{
747struct child_process cmd = CHILD_PROCESS_INIT;748char buf[1];749int i;750
751if (do_reachable_revlist(&cmd, src, NULL, allow_uor) < 0)752return 1;753
754/*755* The commits out of the rev-list are not ancestors of
756* our ref.
757*/
758i = read_in_full(cmd.out, buf, 1);759if (i)760goto error;761close(cmd.out);762cmd.out = -1;763
764/*765* rev-list may have died by encountering a bad commit
766* in the history, in which case we do want to bail out
767* even when it showed no commit.
768*/
769if (finish_command(&cmd))770goto error;771
772/* All the non-tip ones are ancestors of what we advertised */773return 0;774
775error:776if (cmd.out >= 0)777close(cmd.out);778return 1;779}
780
781static void check_non_tip(struct upload_pack_data *data)782{
783int i;784
785/*786* In the normal in-process case without
787* uploadpack.allowReachableSHA1InWant,
788* non-tip requests can never happen.
789*/
790if (!data->stateless_rpc && !(data->allow_uor & ALLOW_REACHABLE_SHA1))791goto error;792if (!has_unreachable(&data->want_obj, data->allow_uor))793/* All the non-tip ones are ancestors of what we advertised */794return;795
796error:797/* Pick one of them (we know there at least is one) */798for (i = 0; i < data->want_obj.nr; i++) {799struct object *o = data->want_obj.objects[i].item;800if (!is_our_ref(o, data->allow_uor)) {801error("git upload-pack: not our ref %s",802oid_to_hex(&o->oid));803packet_writer_error(&data->writer,804"upload-pack: not our ref %s",805oid_to_hex(&o->oid));806exit(128);807}808}809}
810
811static void send_shallow(struct upload_pack_data *data,812struct commit_list *result)813{
814while (result) {815struct object *object = &result->item->object;816if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {817packet_writer_write(&data->writer, "shallow %s",818oid_to_hex(&object->oid));819register_shallow(the_repository, &object->oid);820data->shallow_nr++;821}822result = result->next;823}824}
825
826static void send_unshallow(struct upload_pack_data *data)827{
828int i;829
830for (i = 0; i < data->shallows.nr; i++) {831struct object *object = data->shallows.objects[i].item;832if (object->flags & NOT_SHALLOW) {833struct commit_list *parents;834packet_writer_write(&data->writer, "unshallow %s",835oid_to_hex(&object->oid));836object->flags &= ~CLIENT_SHALLOW;837/*838* We want to _register_ "object" as shallow, but we
839* also need to traverse object's parents to deepen a
840* shallow clone. Unregister it for now so we can
841* parse and add the parents to the want list, then
842* re-register it.
843*/
844unregister_shallow(&object->oid);845object->parsed = 0;846parse_commit_or_die((struct commit *)object);847parents = ((struct commit *)object)->parents;848while (parents) {849add_object_array(&parents->item->object,850NULL, &data->want_obj);851parents = parents->next;852}853add_object_array(object, NULL, &data->extra_edge_obj);854}855/* make sure commit traversal conforms to client */856register_shallow(the_repository, &object->oid);857}858}
859
860static int check_ref(const char *refname_full, const char *referent UNUSED, const struct object_id *oid,861int flag, void *cb_data);862static void deepen(struct upload_pack_data *data, int depth)863{
864if (depth == INFINITE_DEPTH && !is_repository_shallow(the_repository)) {865int i;866
867for (i = 0; i < data->shallows.nr; i++) {868struct object *object = data->shallows.objects[i].item;869object->flags |= NOT_SHALLOW;870}871} else if (data->deepen_relative) {872struct object_array reachable_shallows = OBJECT_ARRAY_INIT;873struct commit_list *result;874
875/*876* Checking for reachable shallows requires that our refs be
877* marked with OUR_REF.
878*/
879refs_head_ref_namespaced(get_main_ref_store(the_repository),880check_ref, data);881for_each_namespaced_ref_1(check_ref, data);882
883get_reachable_list(data, &reachable_shallows);884result = get_shallow_commits(&reachable_shallows,885depth + 1,886SHALLOW, NOT_SHALLOW);887send_shallow(data, result);888free_commit_list(result);889object_array_clear(&reachable_shallows);890} else {891struct commit_list *result;892
893result = get_shallow_commits(&data->want_obj, depth,894SHALLOW, NOT_SHALLOW);895send_shallow(data, result);896free_commit_list(result);897}898
899send_unshallow(data);900}
901
902static void deepen_by_rev_list(struct upload_pack_data *data,903int ac,904const char **av)905{
906struct commit_list *result;907
908disable_commit_graph(the_repository);909result = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW);910send_shallow(data, result);911free_commit_list(result);912send_unshallow(data);913}
914
915/* Returns 1 if a shallow list is sent or 0 otherwise */
916static int send_shallow_list(struct upload_pack_data *data)917{
918int ret = 0;919
920if (data->depth > 0 && data->deepen_rev_list)921die("git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together");922if (data->depth > 0) {923deepen(data, data->depth);924ret = 1;925} else if (data->deepen_rev_list) {926struct strvec av = STRVEC_INIT;927int i;928
929strvec_push(&av, "rev-list");930if (data->deepen_since)931strvec_pushf(&av, "--max-age=%"PRItime, data->deepen_since);932if (oidset_size(&data->deepen_not)) {933const struct object_id *oid;934struct oidset_iter iter;935strvec_push(&av, "--not");936oidset_iter_init(&data->deepen_not, &iter);937while ((oid = oidset_iter_next(&iter)))938strvec_push(&av, oid_to_hex(oid));939strvec_push(&av, "--not");940}941for (i = 0; i < data->want_obj.nr; i++) {942struct object *o = data->want_obj.objects[i].item;943strvec_push(&av, oid_to_hex(&o->oid));944}945deepen_by_rev_list(data, av.nr, av.v);946strvec_clear(&av);947ret = 1;948} else {949if (data->shallows.nr > 0) {950int i;951for (i = 0; i < data->shallows.nr; i++)952register_shallow(the_repository,953&data->shallows.objects[i].item->oid);954}955}956
957data->shallow_nr += data->shallows.nr;958return ret;959}
960
961static int process_shallow(const char *line, struct object_array *shallows)962{
963const char *arg;964if (skip_prefix(line, "shallow ", &arg)) {965struct object_id oid;966struct object *object;967if (get_oid_hex(arg, &oid))968die("invalid shallow line: %s", line);969object = parse_object(the_repository, &oid);970if (!object)971return 1;972if (object->type != OBJ_COMMIT)973die("invalid shallow object %s", oid_to_hex(&oid));974if (!(object->flags & CLIENT_SHALLOW)) {975object->flags |= CLIENT_SHALLOW;976add_object_array(object, NULL, shallows);977}978return 1;979}980
981return 0;982}
983
984static int process_deepen(const char *line, int *depth)985{
986const char *arg;987if (skip_prefix(line, "deepen ", &arg)) {988char *end = NULL;989*depth = (int)strtol(arg, &end, 0);990if (!end || *end || *depth <= 0)991die("Invalid deepen: %s", line);992return 1;993}994
995return 0;996}
997
998static int process_deepen_since(const char *line, timestamp_t *deepen_since, int *deepen_rev_list)999{
1000const char *arg;1001if (skip_prefix(line, "deepen-since ", &arg)) {1002char *end = NULL;1003*deepen_since = parse_timestamp(arg, &end, 0);1004if (!end || *end || !deepen_since ||1005/* revisions.c's max_age -1 is special */1006*deepen_since == -1)1007die("Invalid deepen-since: %s", line);1008*deepen_rev_list = 1;1009return 1;1010}1011return 0;1012}
1013
1014static int process_deepen_not(const char *line, struct oidset *deepen_not, int *deepen_rev_list)1015{
1016const char *arg;1017if (skip_prefix(line, "deepen-not ", &arg)) {1018char *ref = NULL;1019struct object_id oid;1020if (expand_ref(the_repository, arg, strlen(arg), &oid, &ref) != 1)1021die("git upload-pack: ambiguous deepen-not: %s", line);1022oidset_insert(deepen_not, &oid);1023free(ref);1024*deepen_rev_list = 1;1025return 1;1026}1027return 0;1028}
1029
1030NORETURN __attribute__((format(printf,2,3)))1031static void send_err_and_die(struct upload_pack_data *data,1032const char *fmt, ...)1033{
1034struct strbuf buf = STRBUF_INIT;1035va_list ap;1036
1037va_start(ap, fmt);1038strbuf_vaddf(&buf, fmt, ap);1039va_end(ap);1040
1041packet_writer_error(&data->writer, "%s", buf.buf);1042die("%s", buf.buf);1043}
1044
1045static void check_one_filter(struct upload_pack_data *data,1046struct list_objects_filter_options *opts)1047{
1048const char *key = list_object_filter_config_name(opts->choice);1049struct string_list_item *item = string_list_lookup(&data->allowed_filters,1050key);1051int allowed;1052
1053if (item)1054allowed = (intptr_t)item->util;1055else1056allowed = data->allow_filter_fallback;1057
1058if (!allowed)1059send_err_and_die(data, "filter '%s' not supported", key);1060
1061if (opts->choice == LOFC_TREE_DEPTH &&1062opts->tree_exclude_depth > data->tree_filter_max_depth)1063send_err_and_die(data,1064"tree filter allows max depth %lu, but got %lu",1065data->tree_filter_max_depth,1066opts->tree_exclude_depth);1067}
1068
1069static void check_filter_recurse(struct upload_pack_data *data,1070struct list_objects_filter_options *opts)1071{
1072size_t i;1073
1074check_one_filter(data, opts);1075if (opts->choice != LOFC_COMBINE)1076return;1077
1078for (i = 0; i < opts->sub_nr; i++)1079check_filter_recurse(data, &opts->sub[i]);1080}
1081
1082static void die_if_using_banned_filter(struct upload_pack_data *data)1083{
1084check_filter_recurse(data, &data->filter_options);1085}
1086
1087static void receive_needs(struct upload_pack_data *data,1088struct packet_reader *reader)1089{
1090int has_non_tip = 0;1091
1092data->shallow_nr = 0;1093for (;;) {1094struct object *o;1095const char *features;1096struct object_id oid_buf;1097const char *arg;1098size_t feature_len;1099
1100reset_timeout(data->timeout);1101if (packet_reader_read(reader) != PACKET_READ_NORMAL)1102break;1103
1104if (process_shallow(reader->line, &data->shallows))1105continue;1106if (process_deepen(reader->line, &data->depth))1107continue;1108if (process_deepen_since(reader->line, &data->deepen_since, &data->deepen_rev_list))1109continue;1110if (process_deepen_not(reader->line, &data->deepen_not, &data->deepen_rev_list))1111continue;1112
1113if (skip_prefix(reader->line, "filter ", &arg)) {1114if (!data->filter_capability_requested)1115die("git upload-pack: filtering capability not negotiated");1116list_objects_filter_die_if_populated(&data->filter_options);1117parse_list_objects_filter(&data->filter_options, arg);1118die_if_using_banned_filter(data);1119continue;1120}1121
1122if (!skip_prefix(reader->line, "want ", &arg) ||1123parse_oid_hex(arg, &oid_buf, &features))1124die("git upload-pack: protocol error, "1125"expected to get object ID, not '%s'", reader->line);1126
1127if (parse_feature_request(features, "deepen-relative"))1128data->deepen_relative = 1;1129if (parse_feature_request(features, "multi_ack_detailed"))1130data->multi_ack = MULTI_ACK_DETAILED;1131else if (parse_feature_request(features, "multi_ack"))1132data->multi_ack = MULTI_ACK;1133if (parse_feature_request(features, "no-done"))1134data->no_done = 1;1135if (parse_feature_request(features, "thin-pack"))1136data->use_thin_pack = 1;1137if (parse_feature_request(features, "ofs-delta"))1138data->use_ofs_delta = 1;1139if (parse_feature_request(features, "side-band-64k"))1140data->use_sideband = LARGE_PACKET_MAX;1141else if (parse_feature_request(features, "side-band"))1142data->use_sideband = DEFAULT_PACKET_MAX;1143if (parse_feature_request(features, "no-progress"))1144data->no_progress = 1;1145if (parse_feature_request(features, "include-tag"))1146data->use_include_tag = 1;1147if (data->allow_filter &&1148parse_feature_request(features, "filter"))1149data->filter_capability_requested = 1;1150
1151arg = parse_feature_value(features, "session-id", &feature_len, NULL);1152if (arg) {1153char *client_sid = xstrndup(arg, feature_len);1154trace2_data_string("transfer", NULL, "client-sid", client_sid);1155free(client_sid);1156}1157
1158o = parse_object_with_flags(the_repository, &oid_buf,1159PARSE_OBJECT_SKIP_HASH_CHECK |1160PARSE_OBJECT_DISCARD_TREE);1161if (!o) {1162packet_writer_error(&data->writer,1163"upload-pack: not our ref %s",1164oid_to_hex(&oid_buf));1165die("git upload-pack: not our ref %s",1166oid_to_hex(&oid_buf));1167}1168if (!(o->flags & WANTED)) {1169o->flags |= WANTED;1170if (!((data->allow_uor & ALLOW_ANY_SHA1) == ALLOW_ANY_SHA11171|| is_our_ref(o, data->allow_uor)))1172has_non_tip = 1;1173add_object_array(o, NULL, &data->want_obj);1174}1175}1176
1177/*1178* We have sent all our refs already, and the other end
1179* should have chosen out of them. When we are operating
1180* in the stateless RPC mode, however, their choice may
1181* have been based on the set of older refs advertised
1182* by another process that handled the initial request.
1183*/
1184if (has_non_tip)1185check_non_tip(data);1186
1187if (!data->use_sideband && data->daemon_mode)1188data->no_progress = 1;1189
1190if (data->depth == 0 && !data->deepen_rev_list && data->shallows.nr == 0)1191return;1192
1193if (send_shallow_list(data))1194packet_flush(1);1195}
1196
1197/* return non-zero if the ref is hidden, otherwise 0 */
1198static int mark_our_ref(const char *refname, const char *refname_full,1199const struct object_id *oid, const struct strvec *hidden_refs)1200{
1201struct object *o = lookup_unknown_object(the_repository, oid);1202
1203if (ref_is_hidden(refname, refname_full, hidden_refs)) {1204o->flags |= HIDDEN_REF;1205return 1;1206}1207o->flags |= OUR_REF;1208return 0;1209}
1210
1211static int check_ref(const char *refname_full, const char *referent UNUSED,const struct object_id *oid,1212int flag UNUSED, void *cb_data)1213{
1214const char *refname = strip_namespace(refname_full);1215struct upload_pack_data *data = cb_data;1216
1217mark_our_ref(refname, refname_full, oid, &data->hidden_refs);1218return 0;1219}
1220
1221static void format_symref_info(struct strbuf *buf, struct string_list *symref)1222{
1223struct string_list_item *item;1224
1225if (!symref->nr)1226return;1227for_each_string_list_item(item, symref)1228strbuf_addf(buf, " symref=%s:%s", item->string, (char *)item->util);1229}
1230
1231static void format_session_id(struct strbuf *buf, struct upload_pack_data *d) {1232if (d->advertise_sid)1233strbuf_addf(buf, " session-id=%s", trace2_session_id());1234}
1235
1236static void write_v0_ref(struct upload_pack_data *data,1237const char *refname, const char *refname_nons,1238const struct object_id *oid)1239{
1240static const char *capabilities = "multi_ack thin-pack side-band"1241" side-band-64k ofs-delta shallow deepen-since deepen-not"1242" deepen-relative no-progress include-tag multi_ack_detailed";1243struct object_id peeled;1244
1245if (mark_our_ref(refname_nons, refname, oid, &data->hidden_refs))1246return;1247
1248if (capabilities) {1249struct strbuf symref_info = STRBUF_INIT;1250struct strbuf session_id = STRBUF_INIT;1251
1252format_symref_info(&symref_info, &data->symref);1253format_session_id(&session_id, data);1254packet_fwrite_fmt(stdout, "%s %s%c%s%s%s%s%s%s%s object-format=%s agent=%s\n",1255oid_to_hex(oid), refname_nons,12560, capabilities,1257(data->allow_uor & ALLOW_TIP_SHA1) ?1258" allow-tip-sha1-in-want" : "",1259(data->allow_uor & ALLOW_REACHABLE_SHA1) ?1260" allow-reachable-sha1-in-want" : "",1261data->no_done ? " no-done" : "",1262symref_info.buf,1263data->allow_filter ? " filter" : "",1264session_id.buf,1265the_hash_algo->name,1266git_user_agent_sanitized());1267strbuf_release(&symref_info);1268strbuf_release(&session_id);1269data->sent_capabilities = 1;1270} else {1271packet_fwrite_fmt(stdout, "%s %s\n", oid_to_hex(oid), refname_nons);1272}1273capabilities = NULL;1274if (!peel_iterated_oid(the_repository, oid, &peeled))1275packet_fwrite_fmt(stdout, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);1276return;1277}
1278
1279static int send_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,1280int flag UNUSED, void *cb_data)1281{
1282write_v0_ref(cb_data, refname, strip_namespace(refname), oid);1283return 0;1284}
1285
1286static int find_symref(const char *refname, const char *referent UNUSED,1287const struct object_id *oid UNUSED,1288int flag, void *cb_data)1289{
1290const char *symref_target;1291struct string_list_item *item;1292
1293if ((flag & REF_ISSYMREF) == 0)1294return 0;1295symref_target = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),1296refname, 0, NULL, &flag);1297if (!symref_target || (flag & REF_ISSYMREF) == 0)1298die("'%s' is a symref but it is not?", refname);1299item = string_list_append(cb_data, strip_namespace(refname));1300item->util = xstrdup(strip_namespace(symref_target));1301return 0;1302}
1303
1304static int parse_object_filter_config(const char *var, const char *value,1305const struct key_value_info *kvi,1306struct upload_pack_data *data)1307{
1308struct strbuf buf = STRBUF_INIT;1309const char *sub, *key;1310size_t sub_len;1311
1312if (parse_config_key(var, "uploadpackfilter", &sub, &sub_len, &key))1313return 0;1314
1315if (!sub) {1316if (!strcmp(key, "allow"))1317data->allow_filter_fallback = git_config_bool(var, value);1318return 0;1319}1320
1321strbuf_add(&buf, sub, sub_len);1322
1323if (!strcmp(key, "allow"))1324string_list_insert(&data->allowed_filters, buf.buf)->util =1325(void *)(intptr_t)git_config_bool(var, value);1326else if (!strcmp(buf.buf, "tree") && !strcmp(key, "maxdepth")) {1327if (!value) {1328strbuf_release(&buf);1329return config_error_nonbool(var);1330}1331string_list_insert(&data->allowed_filters, buf.buf)->util =1332(void *)(intptr_t)1;1333data->tree_filter_max_depth = git_config_ulong(var, value,1334kvi);1335}1336
1337strbuf_release(&buf);1338return 0;1339}
1340
1341static int upload_pack_config(const char *var, const char *value,1342const struct config_context *ctx,1343void *cb_data)1344{
1345struct upload_pack_data *data = cb_data;1346
1347if (!strcmp("uploadpack.allowtipsha1inwant", var)) {1348if (git_config_bool(var, value))1349data->allow_uor |= ALLOW_TIP_SHA1;1350else1351data->allow_uor &= ~ALLOW_TIP_SHA1;1352} else if (!strcmp("uploadpack.allowreachablesha1inwant", var)) {1353if (git_config_bool(var, value))1354data->allow_uor |= ALLOW_REACHABLE_SHA1;1355else1356data->allow_uor &= ~ALLOW_REACHABLE_SHA1;1357} else if (!strcmp("uploadpack.allowanysha1inwant", var)) {1358if (git_config_bool(var, value))1359data->allow_uor |= ALLOW_ANY_SHA1;1360else1361data->allow_uor &= ~ALLOW_ANY_SHA1;1362} else if (!strcmp("uploadpack.keepalive", var)) {1363data->keepalive = git_config_int(var, value, ctx->kvi);1364if (!data->keepalive)1365data->keepalive = -1;1366} else if (!strcmp("uploadpack.allowfilter", var)) {1367data->allow_filter = git_config_bool(var, value);1368} else if (!strcmp("uploadpack.allowrefinwant", var)) {1369data->allow_ref_in_want = git_config_bool(var, value);1370} else if (!strcmp("uploadpack.allowsidebandall", var)) {1371data->allow_sideband_all = git_config_bool(var, value);1372} else if (!strcmp("uploadpack.blobpackfileuri", var)) {1373if (value)1374data->allow_packfile_uris = 1;1375} else if (!strcmp("core.precomposeunicode", var)) {1376precomposed_unicode = git_config_bool(var, value);1377} else if (!strcmp("transfer.advertisesid", var)) {1378data->advertise_sid = git_config_bool(var, value);1379}1380
1381if (parse_object_filter_config(var, value, ctx->kvi, data) < 0)1382return -1;1383
1384return parse_hide_refs_config(var, value, "uploadpack", &data->hidden_refs);1385}
1386
1387static int upload_pack_protected_config(const char *var, const char *value,1388const struct config_context *ctx UNUSED,1389void *cb_data)1390{
1391struct upload_pack_data *data = cb_data;1392
1393if (!strcmp("uploadpack.packobjectshook", var))1394return git_config_string(&data->pack_objects_hook, var, value);1395return 0;1396}
1397
1398static void get_upload_pack_config(struct repository *r,1399struct upload_pack_data *data)1400{
1401repo_config(r, upload_pack_config, data);1402git_protected_config(upload_pack_protected_config, data);1403
1404data->allow_sideband_all |= git_env_bool("GIT_TEST_SIDEBAND_ALL", 0);1405}
1406
1407void upload_pack(const int advertise_refs, const int stateless_rpc,1408const int timeout)1409{
1410struct packet_reader reader;1411struct upload_pack_data data;1412
1413upload_pack_data_init(&data);1414get_upload_pack_config(the_repository, &data);1415
1416data.stateless_rpc = stateless_rpc;1417data.timeout = timeout;1418if (data.timeout)1419data.daemon_mode = 1;1420
1421refs_head_ref_namespaced(get_main_ref_store(the_repository),1422find_symref, &data.symref);1423
1424if (advertise_refs || !data.stateless_rpc) {1425reset_timeout(data.timeout);1426if (advertise_refs)1427data.no_done = 1;1428refs_head_ref_namespaced(get_main_ref_store(the_repository),1429send_ref, &data);1430for_each_namespaced_ref_1(send_ref, &data);1431if (!data.sent_capabilities) {1432const char *refname = "capabilities^{}";1433write_v0_ref(&data, refname, refname, null_oid());1434}1435/*1436* fflush stdout before calling advertise_shallow_grafts because send_ref
1437* uses stdio.
1438*/
1439fflush_or_die(stdout);1440advertise_shallow_grafts(1);1441packet_flush(1);1442} else {1443refs_head_ref_namespaced(get_main_ref_store(the_repository),1444check_ref, &data);1445for_each_namespaced_ref_1(check_ref, &data);1446}1447
1448if (!advertise_refs) {1449packet_reader_init(&reader, 0, NULL, 0,1450PACKET_READ_CHOMP_NEWLINE |1451PACKET_READ_DIE_ON_ERR_PACKET);1452
1453receive_needs(&data, &reader);1454
1455/*1456* An EOF at this exact point in negotiation should be
1457* acceptable from stateless clients as they will consume the
1458* shallow list before doing subsequent rpc with haves/etc.
1459*/
1460if (data.stateless_rpc)1461reader.options |= PACKET_READ_GENTLE_ON_EOF;1462
1463if (data.want_obj.nr &&1464packet_reader_peek(&reader) != PACKET_READ_EOF) {1465reader.options &= ~PACKET_READ_GENTLE_ON_EOF;1466get_common_commits(&data, &reader);1467create_pack_file(&data, NULL);1468}1469}1470
1471upload_pack_data_clear(&data);1472}
1473
1474static int parse_want(struct packet_writer *writer, const char *line,1475struct object_array *want_obj)1476{
1477const char *arg;1478if (skip_prefix(line, "want ", &arg)) {1479struct object_id oid;1480struct object *o;1481
1482if (get_oid_hex(arg, &oid))1483die("git upload-pack: protocol error, "1484"expected to get oid, not '%s'", line);1485
1486o = parse_object_with_flags(the_repository, &oid,1487PARSE_OBJECT_SKIP_HASH_CHECK |1488PARSE_OBJECT_DISCARD_TREE);1489
1490if (!o) {1491packet_writer_error(writer,1492"upload-pack: not our ref %s",1493oid_to_hex(&oid));1494die("git upload-pack: not our ref %s",1495oid_to_hex(&oid));1496}1497
1498if (!(o->flags & WANTED)) {1499o->flags |= WANTED;1500add_object_array(o, NULL, want_obj);1501}1502
1503return 1;1504}1505
1506return 0;1507}
1508
1509static int parse_want_ref(struct packet_writer *writer, const char *line,1510struct strmap *wanted_refs,1511struct strvec *hidden_refs,1512struct object_array *want_obj)1513{
1514const char *refname_nons;1515if (skip_prefix(line, "want-ref ", &refname_nons)) {1516struct object_id oid;1517struct object *o = NULL;1518struct strbuf refname = STRBUF_INIT;1519
1520strbuf_addf(&refname, "%s%s", get_git_namespace(), refname_nons);1521if (ref_is_hidden(refname_nons, refname.buf, hidden_refs) ||1522refs_read_ref(get_main_ref_store(the_repository), refname.buf, &oid)) {1523packet_writer_error(writer, "unknown ref %s", refname_nons);1524die("unknown ref %s", refname_nons);1525}1526strbuf_release(&refname);1527
1528if (strmap_put(wanted_refs, refname_nons, oiddup(&oid))) {1529packet_writer_error(writer, "duplicate want-ref %s",1530refname_nons);1531die("duplicate want-ref %s", refname_nons);1532}1533
1534if (!starts_with(refname_nons, "refs/tags/")) {1535struct commit *commit = lookup_commit_in_graph(the_repository, &oid);1536if (commit)1537o = &commit->object;1538}1539
1540if (!o)1541o = parse_object_or_die(&oid, refname_nons);1542
1543if (!(o->flags & WANTED)) {1544o->flags |= WANTED;1545add_object_array(o, NULL, want_obj);1546}1547
1548return 1;1549}1550
1551return 0;1552}
1553
1554static int parse_have(const char *line, struct upload_pack_data *data)1555{
1556const char *arg;1557if (skip_prefix(line, "have ", &arg)) {1558struct object_id oid;1559
1560got_oid(data, arg, &oid);1561data->seen_haves = 1;1562return 1;1563}1564
1565return 0;1566}
1567
1568static void trace2_fetch_info(struct upload_pack_data *data)1569{
1570struct json_writer jw = JSON_WRITER_INIT;1571
1572jw_object_begin(&jw, 0);1573jw_object_intmax(&jw, "haves", data->have_obj.nr);1574jw_object_intmax(&jw, "wants", data->want_obj.nr);1575jw_object_intmax(&jw, "want-refs", strmap_get_size(&data->wanted_refs));1576jw_object_intmax(&jw, "depth", data->depth);1577jw_object_intmax(&jw, "shallows", data->shallows.nr);1578jw_object_bool(&jw, "deepen-since", data->deepen_since);1579jw_object_intmax(&jw, "deepen-not", oidset_size(&data->deepen_not));1580jw_object_bool(&jw, "deepen-relative", data->deepen_relative);1581if (data->filter_options.choice)1582jw_object_string(&jw, "filter", list_object_filter_config_name(data->filter_options.choice));1583else1584jw_object_null(&jw, "filter");1585jw_end(&jw);1586
1587trace2_data_json("upload-pack", the_repository, "fetch-info", &jw);1588
1589jw_release(&jw);1590}
1591
1592static void process_args(struct packet_reader *request,1593struct upload_pack_data *data)1594{
1595while (packet_reader_read(request) == PACKET_READ_NORMAL) {1596const char *arg = request->line;1597const char *p;1598
1599/* process want */1600if (parse_want(&data->writer, arg, &data->want_obj))1601continue;1602if (data->allow_ref_in_want &&1603parse_want_ref(&data->writer, arg, &data->wanted_refs,1604&data->hidden_refs, &data->want_obj))1605continue;1606/* process have line */1607if (parse_have(arg, data))1608continue;1609
1610/* process args like thin-pack */1611if (!strcmp(arg, "thin-pack")) {1612data->use_thin_pack = 1;1613continue;1614}1615if (!strcmp(arg, "ofs-delta")) {1616data->use_ofs_delta = 1;1617continue;1618}1619if (!strcmp(arg, "no-progress")) {1620data->no_progress = 1;1621continue;1622}1623if (!strcmp(arg, "include-tag")) {1624data->use_include_tag = 1;1625continue;1626}1627if (!strcmp(arg, "done")) {1628data->done = 1;1629continue;1630}1631if (!strcmp(arg, "wait-for-done")) {1632data->wait_for_done = 1;1633continue;1634}1635
1636/* Shallow related arguments */1637if (process_shallow(arg, &data->shallows))1638continue;1639if (process_deepen(arg, &data->depth))1640continue;1641if (process_deepen_since(arg, &data->deepen_since,1642&data->deepen_rev_list))1643continue;1644if (process_deepen_not(arg, &data->deepen_not,1645&data->deepen_rev_list))1646continue;1647if (!strcmp(arg, "deepen-relative")) {1648data->deepen_relative = 1;1649continue;1650}1651
1652if (data->allow_filter && skip_prefix(arg, "filter ", &p)) {1653list_objects_filter_die_if_populated(&data->filter_options);1654parse_list_objects_filter(&data->filter_options, p);1655die_if_using_banned_filter(data);1656continue;1657}1658
1659if (data->allow_sideband_all &&1660!strcmp(arg, "sideband-all")) {1661data->writer.use_sideband = 1;1662continue;1663}1664
1665if (data->allow_packfile_uris &&1666skip_prefix(arg, "packfile-uris ", &p)) {1667if (data->uri_protocols.nr)1668send_err_and_die(data,1669"multiple packfile-uris lines forbidden");1670string_list_split(&data->uri_protocols, p, ',', -1);1671continue;1672}1673
1674/* ignore unknown lines maybe? */1675die("unexpected line: '%s'", arg);1676}1677
1678if (data->uri_protocols.nr && !data->writer.use_sideband)1679string_list_clear(&data->uri_protocols, 0);1680
1681if (request->status != PACKET_READ_FLUSH)1682die(_("expected flush after fetch arguments"));1683
1684if (trace2_is_enabled())1685trace2_fetch_info(data);1686}
1687
1688static int send_acks(struct upload_pack_data *data, struct object_array *acks)1689{
1690int i;1691
1692packet_writer_write(&data->writer, "acknowledgments\n");1693
1694/* Send Acks */1695if (!acks->nr)1696packet_writer_write(&data->writer, "NAK\n");1697
1698for (i = 0; i < acks->nr; i++) {1699packet_writer_write(&data->writer, "ACK %s\n",1700oid_to_hex(&acks->objects[i].item->oid));1701}1702
1703if (!data->wait_for_done && ok_to_give_up(data)) {1704/* Send Ready */1705packet_writer_write(&data->writer, "ready\n");1706return 1;1707}1708
1709return 0;1710}
1711
1712static int process_haves_and_send_acks(struct upload_pack_data *data)1713{
1714int ret = 0;1715
1716if (data->done) {1717ret = 1;1718} else if (send_acks(data, &data->have_obj)) {1719packet_writer_delim(&data->writer);1720ret = 1;1721} else {1722/* Add Flush */1723packet_writer_flush(&data->writer);1724ret = 0;1725}1726
1727return ret;1728}
1729
1730static void send_wanted_ref_info(struct upload_pack_data *data)1731{
1732struct hashmap_iter iter;1733const struct strmap_entry *e;1734
1735if (strmap_empty(&data->wanted_refs))1736return;1737
1738packet_writer_write(&data->writer, "wanted-refs\n");1739
1740strmap_for_each_entry(&data->wanted_refs, &iter, e) {1741packet_writer_write(&data->writer, "%s %s\n",1742oid_to_hex(e->value),1743e->key);1744}1745
1746packet_writer_delim(&data->writer);1747}
1748
1749static void send_shallow_info(struct upload_pack_data *data)1750{
1751/* No shallow info needs to be sent */1752if (!data->depth && !data->deepen_rev_list && !data->shallows.nr &&1753!is_repository_shallow(the_repository))1754return;1755
1756packet_writer_write(&data->writer, "shallow-info\n");1757
1758if (!send_shallow_list(data) &&1759is_repository_shallow(the_repository))1760deepen(data, INFINITE_DEPTH);1761
1762packet_delim(1);1763}
1764
1765enum fetch_state {1766FETCH_PROCESS_ARGS = 0,1767FETCH_SEND_ACKS,1768FETCH_SEND_PACK,1769FETCH_DONE,1770};1771
1772int upload_pack_v2(struct repository *r, struct packet_reader *request)1773{
1774enum fetch_state state = FETCH_PROCESS_ARGS;1775struct upload_pack_data data;1776
1777clear_object_flags(ALL_FLAGS);1778
1779upload_pack_data_init(&data);1780data.use_sideband = LARGE_PACKET_MAX;1781get_upload_pack_config(r, &data);1782
1783while (state != FETCH_DONE) {1784switch (state) {1785case FETCH_PROCESS_ARGS:1786process_args(request, &data);1787
1788if (!data.want_obj.nr && !data.wait_for_done) {1789/*1790* Request didn't contain any 'want' lines (and
1791* the request does not contain
1792* "wait-for-done", in which it is reasonable
1793* to just send 'have's without 'want's); guess
1794* they didn't want anything.
1795*/
1796state = FETCH_DONE;1797} else if (data.seen_haves) {1798/*1799* Request had 'have' lines, so lets ACK them.
1800*/
1801state = FETCH_SEND_ACKS;1802} else {1803/*1804* Request had 'want's but no 'have's so we can
1805* immedietly go to construct and send a pack.
1806*/
1807state = FETCH_SEND_PACK;1808}1809break;1810case FETCH_SEND_ACKS:1811if (process_haves_and_send_acks(&data))1812state = FETCH_SEND_PACK;1813else1814state = FETCH_DONE;1815break;1816case FETCH_SEND_PACK:1817send_wanted_ref_info(&data);1818send_shallow_info(&data);1819
1820if (data.uri_protocols.nr) {1821create_pack_file(&data, &data.uri_protocols);1822} else {1823packet_writer_write(&data.writer, "packfile\n");1824create_pack_file(&data, NULL);1825}1826state = FETCH_DONE;1827break;1828case FETCH_DONE:1829continue;1830}1831}1832
1833upload_pack_data_clear(&data);1834return 0;1835}
1836
1837int upload_pack_advertise(struct repository *r,1838struct strbuf *value)1839{
1840struct upload_pack_data data;1841
1842upload_pack_data_init(&data);1843get_upload_pack_config(r, &data);1844
1845if (value) {1846strbuf_addstr(value, "shallow wait-for-done");1847
1848if (data.allow_filter)1849strbuf_addstr(value, " filter");1850
1851if (data.allow_ref_in_want)1852strbuf_addstr(value, " ref-in-want");1853
1854if (data.allow_sideband_all)1855strbuf_addstr(value, " sideband-all");1856
1857if (data.allow_packfile_uris)1858strbuf_addstr(value, " packfile-uris");1859}1860
1861upload_pack_data_clear(&data);1862
1863return 1;1864}
1865