From: Junio C Hamano Date: Tue, 29 Sep 2015 02:16:54 +0000 (-0700) Subject: Sync with v2.5.4 X-Git-Tag: v2.6.1~1 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/3adc4ec7b9e1d2118501728a75a5b93d971974fa?ds=inline;hp=-c Sync with v2.5.4 --- 3adc4ec7b9e1d2118501728a75a5b93d971974fa diff --combined Documentation/git.txt index b37cfcefcd,1a262757dc..f9a7fb94c5 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@@ -43,22 -43,19 +43,24 @@@ unreleased) version of Git, that is ava branch of the `git.git` repository. Documentation for older releases are available here: +* link:v2.6.0/git.html[documentation for release 2.6] + +* release notes for + link:RelNotes/2.6.0.txt[2.6]. + - * link:v2.5.3/git.html[documentation for release 2.5.3] + * link:v2.5.4/git.html[documentation for release 2.5.4] * release notes for + link:RelNotes/2.5.4.txt[2.5.4], link:RelNotes/2.5.3.txt[2.5.3], link:RelNotes/2.5.2.txt[2.5.2], link:RelNotes/2.5.1.txt[2.5.1], link:RelNotes/2.5.0.txt[2.5]. - * link:v2.4.9/git.html[documentation for release 2.4.9] + * link:v2.4.10/git.html[documentation for release 2.4.10] * release notes for + link:RelNotes/2.4.10.txt[2.4.10], link:RelNotes/2.4.9.txt[2.4.9], link:RelNotes/2.4.8.txt[2.4.8], link:RelNotes/2.4.7.txt[2.4.7], @@@ -70,9 -67,10 +72,10 @@@ link:RelNotes/2.4.1.txt[2.4.1], link:RelNotes/2.4.0.txt[2.4]. - * link:v2.3.9/git.html[documentation for release 2.3.9] + * link:v2.3.10/git.html[documentation for release 2.3.10] * release notes for + link:RelNotes/2.3.10.txt[2.3.10], link:RelNotes/2.3.9.txt[2.3.9], link:RelNotes/2.3.8.txt[2.3.8], link:RelNotes/2.3.7.txt[2.3.7], @@@ -1021,20 -1019,9 +1024,20 @@@ Unsetting the variable, or setting it t Enables trace messages for all packets coming in or out of a given program. This can help with debugging object negotiation or other protocol issues. Tracing is turned off at a packet - starting with "PACK". + starting with "PACK" (but see 'GIT_TRACE_PACKFILE' below). See 'GIT_TRACE' for available trace output options. +'GIT_TRACE_PACKFILE':: + Enables tracing of packfiles sent or received by a + given program. Unlike other trace output, this trace is + verbatim: no headers, and no quoting of binary data. You almost + certainly want to direct into a file (e.g., + `GIT_TRACE_PACKFILE=/tmp/my.pack`) rather than displaying it on + the terminal or mixing it with other trace output. ++ +Note that this is currently only implemented for the client side +of clones and fetches. + 'GIT_TRACE_PERFORMANCE':: Enables performance related trace messages, e.g. total execution time of each Git command. @@@ -1092,6 -1079,33 +1095,33 @@@ GIT_ICASE_PATHSPECS: an operation has touched every ref (e.g., because you are cloning a repository to make a backup). + `GIT_ALLOW_PROTOCOL`:: + If set, provide a colon-separated list of protocols which are + allowed to be used with fetch/push/clone. This is useful to + restrict recursive submodule initialization from an untrusted + repository. Any protocol not mentioned will be disallowed (i.e., + this is a whitelist, not a blacklist). If the variable is not + set at all, all protocols are enabled. The protocol names + currently used by git are: + + - `file`: any local file-based path (including `file://` URLs, + or local paths) + + - `git`: the anonymous git protocol over a direct TCP + connection (or proxy, if configured) + + - `ssh`: git over ssh (including `host:path` syntax, + `git+ssh://`, etc). + + - `rsync`: git over rsync + + - `http`: git over http, both "smart http" and "dumb http". + Note that this does _not_ include `https`; if you want both, + you should specify both as `http:https`. + + - any external helpers are named by their protocol (e.g., use + `hg` to allow the `git-remote-hg` helper) + Discussion[[Discussion]] ------------------------ diff --combined builtin/blame.c index 4db01c195c,191368bfab..245d253d04 --- a/builtin/blame.c +++ b/builtin/blame.c @@@ -6,7 -6,6 +6,7 @@@ */ #include "cache.h" +#include "refs.h" #include "builtin.h" #include "blob.h" #include "commit.h" @@@ -51,7 -50,7 +51,7 @@@ static int xdl_opts static int abbrev = -1; static int no_whole_file_rename; -static enum date_mode blame_date_mode = DATE_ISO8601; +static struct date_mode blame_date_mode = { DATE_ISO8601 }; static size_t blame_date_width; static struct string_list mailmap; @@@ -974,7 -973,10 +974,10 @@@ static void pass_blame_to_parent(struc fill_origin_blob(&sb->revs->diffopt, target, &file_o); num_get_patch++; - diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d); + if (diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d)) + die("unable to generate diff (%s -> %s)", + sha1_to_hex(parent->commit->object.sha1), + sha1_to_hex(target->commit->object.sha1)); /* The rest are the same as the parent */ blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent); *d.dstq = NULL; @@@ -1120,7 -1122,9 +1123,9 @@@ static void find_copy_in_blob(struct sc * file_p partially may match that image. */ memset(split, 0, sizeof(struct blame_entry [3])); - diff_hunks(file_p, &file_o, 1, handle_split_cb, &d); + if (diff_hunks(file_p, &file_o, 1, handle_split_cb, &d)) + die("unable to generate diff (%s)", + sha1_to_hex(parent->commit->object.sha1)); /* remainder, if any, all match the preimage */ handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split); } @@@ -1828,7 -1832,7 +1833,7 @@@ static const char *format_time(unsigne size_t time_width; int tz; tz = atoi(tz_str); - time_str = show_date(time, tz, blame_date_mode); + time_str = show_date(time, tz, &blame_date_mode); strbuf_addstr(&time_buf, time_str); /* * Add space paddings to time_buf to display a fixed width @@@ -2188,7 -2192,7 +2193,7 @@@ static int git_blame_config(const char if (!strcmp(var, "blame.date")) { if (!value) return config_error_nonbool(var); - blame_date_mode = parse_date_format(value); + parse_date_format(value, &blame_date_mode); return 0; } @@@ -2227,19 -2231,20 +2232,19 @@@ static struct commit_list **append_pare static void append_merge_parents(struct commit_list **tail) { int merge_head; - const char *merge_head_file = git_path("MERGE_HEAD"); struct strbuf line = STRBUF_INIT; - merge_head = open(merge_head_file, O_RDONLY); + merge_head = open(git_path_merge_head(), O_RDONLY); if (merge_head < 0) { if (errno == ENOENT) return; - die("cannot open '%s' for reading", merge_head_file); + die("cannot open '%s' for reading", git_path_merge_head()); } while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) { unsigned char sha1[20]; if (line.len < 40 || get_sha1_hex(line.buf, sha1)) - die("unknown line in '%s': %s", merge_head_file, line.buf); + die("unknown line in '%s': %s", git_path_merge_head(), line.buf); tail = append_parent(tail, sha1); } close(merge_head); @@@ -2569,13 -2574,13 +2574,13 @@@ parse_done if (cmd_is_annotate) { output_option |= OUTPUT_ANNOTATE_COMPAT; - blame_date_mode = DATE_ISO8601; + blame_date_mode.type = DATE_ISO8601; } else { blame_date_mode = revs.date_mode; } /* The maximum width used to show the dates */ - switch (blame_date_mode) { + switch (blame_date_mode.type) { case DATE_RFC2822: blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700"); break; @@@ -2604,9 -2609,6 +2609,9 @@@ case DATE_NORMAL: blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700"); break; + case DATE_STRFTIME: + blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */ + break; } blame_date_width -= 1; /* strip the null */ diff --combined builtin/rerere.c index 12535c9b4f,be55e0d2a7..88e1359ebc --- a/builtin/rerere.c +++ b/builtin/rerere.c @@@ -29,9 -29,10 +29,10 @@@ static int diff_two(const char *file1, xdemitconf_t xecfg; xdemitcb_t ecb; mmfile_t minus, plus; + int ret; if (read_mmfile(&minus, file1) || read_mmfile(&plus, file2)) - return 1; + return -1; printf("--- a/%s\n+++ b/%s\n", label1, label2); fflush(stdout); @@@ -40,17 -41,17 +41,17 @@@ memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 3; ecb.outf = outf; - xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb); + ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb); free(minus.ptr); free(plus.ptr); - return 0; + return ret; } int cmd_rerere(int argc, const char **argv, const char *prefix) { struct string_list merge_rr = STRING_LIST_INIT_DUP; - int i, fd, autoupdate = -1, flags = 0; + int i, autoupdate = -1, flags = 0; struct option options[] = { OPT_SET_INT(0, "rerere-autoupdate", &autoupdate, @@@ -79,16 -80,18 +80,16 @@@ return rerere_forget(&pathspec); } - fd = setup_rerere(&merge_rr, flags); - if (fd < 0) - return 0; - if (!strcmp(argv[0], "clear")) { rerere_clear(&merge_rr); } else if (!strcmp(argv[0], "gc")) rerere_gc(&merge_rr); - else if (!strcmp(argv[0], "status")) + else if (!strcmp(argv[0], "status")) { + if (setup_rerere(&merge_rr, flags | RERERE_READONLY) < 0) + return 0; for (i = 0; i < merge_rr.nr; i++) printf("%s\n", merge_rr.items[i].string); - else if (!strcmp(argv[0], "remaining")) { + } else if (!strcmp(argv[0], "remaining")) { rerere_remaining(&merge_rr); for (i = 0; i < merge_rr.nr; i++) { if (merge_rr.items[i].util != RERERE_RESOLVED) @@@ -98,15 -101,14 +99,16 @@@ * string_list_clear() */ merge_rr.items[i].util = NULL; } - } else if (!strcmp(argv[0], "diff")) + } else if (!strcmp(argv[0], "diff")) { + if (setup_rerere(&merge_rr, flags | RERERE_READONLY) < 0) + return 0; for (i = 0; i < merge_rr.nr; i++) { const char *path = merge_rr.items[i].string; const char *name = (const char *)merge_rr.items[i].util; - diff_two(rerere_path(name, "preimage"), path, path, path); + if (diff_two(rerere_path(name, "preimage"), path, path, path)) + die("unable to generate diff for %s", name); } - else + } else usage_with_options(rerere_usage, options); string_list_clear(&merge_rr, 1); diff --combined diff.c index 08508f6a20,71f0274ce0..46260ed7a1 --- a/diff.c +++ b/diff.c @@@ -2,7 -2,6 +2,7 @@@ * Copyright (C) 2005 Junio C Hamano */ #include "cache.h" +#include "tempfile.h" #include "quote.h" #include "diff.h" #include "diffcore.h" @@@ -14,7 -13,6 +14,7 @@@ #include "utf8.h" #include "userdiff.h" #include "sigchain.h" +#include "submodule-config.h" #include "submodule.h" #include "ll-merge.h" #include "string-list.h" @@@ -310,26 -308,11 +310,26 @@@ static const char *external_diff(void return external_diff_cmd; } +/* + * Keep track of files used for diffing. Sometimes such an entry + * refers to a temporary file, sometimes to an existing file, and + * sometimes to "/dev/null". + */ static struct diff_tempfile { - const char *name; /* filename external diff should read from */ + /* + * filename external diff should read from, or NULL if this + * entry is currently not in use: + */ + const char *name; + char hex[41]; char mode[10]; - char tmp_path[PATH_MAX]; + + /* + * If this diff_tempfile instance refers to a temporary file, + * this tempfile object is used to manage its lifetime. + */ + struct tempfile tempfile; } diff_temp[2]; typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); @@@ -614,16 -597,25 +614,16 @@@ static struct diff_tempfile *claim_diff die("BUG: diff is failing to clean up its tempfiles"); } -static int remove_tempfile_installed; - static void remove_tempfile(void) { int i; for (i = 0; i < ARRAY_SIZE(diff_temp); i++) { - if (diff_temp[i].name == diff_temp[i].tmp_path) - unlink_or_warn(diff_temp[i].name); + if (is_tempfile_active(&diff_temp[i].tempfile)) + delete_tempfile(&diff_temp[i].tempfile); diff_temp[i].name = NULL; } } -static void remove_tempfile_on_signal(int signo) -{ - remove_tempfile(); - sigchain_pop(signo); - raise(signo); -} - static void print_line_count(FILE *file, int count) { switch (count) { @@@ -1041,8 -1033,9 +1041,9 @@@ static void diff_words_show(struct diff xpp.flags = 0; /* as only the hunk header will be parsed, we need a 0-context */ xecfg.ctxlen = 0; - xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, - &xpp, &xecfg); + if (xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, + &xpp, &xecfg)) + die("unable to generate word diff"); free(minus.ptr); free(plus.ptr); if (diff_words->current_plus != diff_words->plus.text.ptr + @@@ -2449,8 -2442,9 +2450,9 @@@ static void builtin_diff(const char *na xecfg.ctxlen = strtoul(v, NULL, 10); if (o->word_diff) init_diff_words_data(&ecbdata, o, one, two); - xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, - &xpp, &xecfg); + if (xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, + &xpp, &xecfg)) + die("unable to generate diff for %s", one->path); if (o->word_diff) free_diff_words_data(&ecbdata); if (textconv_one) @@@ -2527,8 -2521,9 +2529,9 @@@ static void builtin_diffstat(const cha xpp.flags = o->xdl_opts; xecfg.ctxlen = o->context; xecfg.interhunkctxlen = o->interhunkcontext; - xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat, - &xpp, &xecfg); + if (xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat, + &xpp, &xecfg)) + die("unable to generate diffstat for %s", one->path); } diff_free_filespec_data(one); @@@ -2574,8 -2569,9 +2577,9 @@@ static void builtin_checkdiff(const cha memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 1; /* at least one context line */ xpp.flags = 0; - xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data, - &xpp, &xecfg); + if (xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data, + &xpp, &xecfg)) + die("unable to generate checkdiff for %s", one->path); if (data.ws_rule & WS_BLANK_AT_EOF) { struct emit_callback ecbdata; @@@ -2866,7 -2862,8 +2870,7 @@@ static void prep_temp_blob(const char * strbuf_addstr(&template, "XXXXXX_"); strbuf_addstr(&template, base); - fd = git_mkstemps(temp->tmp_path, PATH_MAX, template.buf, - strlen(base) + 1); + fd = mks_tempfile_ts(&temp->tempfile, template.buf, strlen(base) + 1); if (fd < 0) die_errno("unable to create temp-file"); if (convert_to_working_tree(path, @@@ -2876,8 -2873,8 +2880,8 @@@ } if (write_in_full(fd, blob, size) != size) die_errno("unable to write temp-file"); - close(fd); - temp->name = temp->tmp_path; + close_tempfile(&temp->tempfile); + temp->name = get_tempfile_path(&temp->tempfile); strcpy(temp->hex, sha1_to_hex(sha1)); temp->hex[40] = 0; sprintf(temp->mode, "%06o", mode); @@@ -2902,6 -2899,12 +2906,6 @@@ static struct diff_tempfile *prepare_te return temp; } - if (!remove_tempfile_installed) { - atexit(remove_tempfile); - sigchain_push_common(remove_tempfile_on_signal); - remove_tempfile_installed = 1; - } - if (!S_ISGITLINK(one->mode) && (!one->sha1_valid || reuse_worktree_file(name, one->sha1, 1))) { @@@ -3821,10 -3824,9 +3825,10 @@@ int diff_opt_parse(struct diff_options DIFF_OPT_SET(options, FIND_COPIES_HARDER); else if (!strcmp(arg, "--follow")) DIFF_OPT_SET(options, FOLLOW_RENAMES); - else if (!strcmp(arg, "--no-follow")) + else if (!strcmp(arg, "--no-follow")) { DIFF_OPT_CLR(options, FOLLOW_RENAMES); - else if (!strcmp(arg, "--color")) + DIFF_OPT_CLR(options, DEFAULT_FOLLOW_RENAMES); + } else if (!strcmp(arg, "--color")) options->use_color = 1; else if (skip_prefix(arg, "--color=", &arg)) { int value = git_config_colorbool(NULL, arg); @@@ -4510,8 -4512,10 +4514,10 @@@ static int diff_get_patch_id(struct dif xpp.flags = 0; xecfg.ctxlen = 3; xecfg.flags = 0; - xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data, - &xpp, &xecfg); + if (xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data, + &xpp, &xecfg)) + return error("unable to generate patch-id diff for %s", + p->one->path); } git_SHA1_Final(sha1, &ctx); diff --combined http.c index 9dce38025c,45348fb9bd..0f924a8b48 --- a/http.c +++ b/http.c @@@ -9,6 -9,7 +9,7 @@@ #include "version.h" #include "pkt-line.h" #include "gettext.h" + #include "transport.h" int active_requests; int http_is_verbose; @@@ -37,20 -38,6 +38,20 @@@ static int curl_ssl_verify = -1 static int curl_ssl_try; static const char *ssl_cert; static const char *ssl_cipherlist; +static const char *ssl_version; +static struct { + const char *name; + long ssl_version; +} sslversions[] = { + { "sslv2", CURL_SSLVERSION_SSLv2 }, + { "sslv3", CURL_SSLVERSION_SSLv3 }, + { "tlsv1", CURL_SSLVERSION_TLSv1 }, +#if LIBCURL_VERSION_NUM >= 0x072200 + { "tlsv1.0", CURL_SSLVERSION_TLSv1_0 }, + { "tlsv1.1", CURL_SSLVERSION_TLSv1_1 }, + { "tlsv1.2", CURL_SSLVERSION_TLSv1_2 }, +#endif +}; #if LIBCURL_VERSION_NUM >= 0x070903 static const char *ssl_key; #endif @@@ -204,8 -191,6 +205,8 @@@ static int http_options(const char *var } if (!strcmp("http.sslcipherlist", var)) return git_config_string(&ssl_cipherlist, var, value); + if (!strcmp("http.sslversion", var)) + return git_config_string(&ssl_version, var, value); if (!strcmp("http.sslcert", var)) return git_config_string(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 @@@ -356,6 -341,7 +357,7 @@@ static void set_curl_keepalive(CURL *c static CURL *get_curl_handle(void) { CURL *result = curl_easy_init(); + long allowed_protocols = 0; if (!result) die("curl_easy_init failed"); @@@ -380,24 -366,9 +382,24 @@@ if (http_proactive_auth) init_curl_http_auth(result); + if (getenv("GIT_SSL_VERSION")) + ssl_version = getenv("GIT_SSL_VERSION"); + if (ssl_version && *ssl_version) { + int i; + for (i = 0; i < ARRAY_SIZE(sslversions); i++) { + if (!strcmp(ssl_version, sslversions[i].name)) { + curl_easy_setopt(result, CURLOPT_SSLVERSION, + sslversions[i].ssl_version); + break; + } + } + if (i == ARRAY_SIZE(sslversions)) + warning("unsupported ssl version %s: using default", + ssl_version); + } + if (getenv("GIT_SSL_CIPHER_LIST")) ssl_cipherlist = getenv("GIT_SSL_CIPHER_LIST"); - if (ssl_cipherlist != NULL && *ssl_cipherlist) curl_easy_setopt(result, CURLOPT_SSL_CIPHER_LIST, ssl_cipherlist); @@@ -425,11 -396,27 +427,27 @@@ } curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(result, CURLOPT_MAXREDIRS, 20); #if LIBCURL_VERSION_NUM >= 0x071301 curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL); #elif LIBCURL_VERSION_NUM >= 0x071101 curl_easy_setopt(result, CURLOPT_POST301, 1); #endif + #if LIBCURL_VERSION_NUM >= 0x071304 + if (is_transport_allowed("http")) + allowed_protocols |= CURLPROTO_HTTP; + if (is_transport_allowed("https")) + allowed_protocols |= CURLPROTO_HTTPS; + if (is_transport_allowed("ftp")) + allowed_protocols |= CURLPROTO_FTP; + if (is_transport_allowed("ftps")) + allowed_protocols |= CURLPROTO_FTPS; + curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, allowed_protocols); + #else + if (transport_restrict_protocols()) + warning("protocol restrictions not applied to curl redirects because\n" + "your curl version is too old (>= 7.19.4)"); + #endif if (getenv("GIT_CURL_VERBOSE")) curl_easy_setopt(result, CURLOPT_VERBOSE, 1); @@@ -1349,7 -1336,7 +1367,7 @@@ static int http_get_file(const char *ur ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options); fclose(result); - if (ret == HTTP_OK && move_temp_to_file(tmpfile.buf, filename)) + if (ret == HTTP_OK && finalize_object_file(tmpfile.buf, filename)) ret = HTTP_ERROR; cleanup: strbuf_release(&tmpfile); @@@ -1436,7 -1423,7 +1454,7 @@@ static int fetch_and_setup_pack_index(s ret = verify_pack_index(new_pack); if (!ret) { close_pack_index(new_pack); - ret = move_temp_to_file(tmp_idx, sha1_pack_index_name(sha1)); + ret = finalize_object_file(tmp_idx, sha1_pack_index_name(sha1)); } free(tmp_idx); if (ret) @@@ -1548,8 -1535,8 +1566,8 @@@ int finish_http_pack_request(struct htt unlink(sha1_pack_index_name(p->sha1)); - if (move_temp_to_file(preq->tmpfile, sha1_pack_name(p->sha1)) - || move_temp_to_file(tmp_idx, sha1_pack_index_name(p->sha1))) { + if (finalize_object_file(preq->tmpfile, sha1_pack_name(p->sha1)) + || finalize_object_file(tmp_idx, sha1_pack_index_name(p->sha1))) { free(tmp_idx); return -1; } @@@ -1813,7 -1800,7 +1831,7 @@@ int finish_http_object_request(struct h return -1; } freq->rename = - move_temp_to_file(freq->tmpfile, sha1_file_name(freq->sha1)); + finalize_object_file(freq->tmpfile, sha1_file_name(freq->sha1)); return freq->rename; } diff --combined transport-helper.c index 99f1ace1f2,12f50d5b94..63d54271b0 --- a/transport-helper.c +++ b/transport-helper.c @@@ -257,6 -257,7 +257,6 @@@ static const char *boolean_options[] = TRANS_OPT_THIN, TRANS_OPT_KEEP, TRANS_OPT_FOLLOWTAGS, - TRANS_OPT_PUSH_CERT }; static int set_helper_option(struct transport *transport, @@@ -763,21 -764,6 +763,21 @@@ static int push_update_refs_status(stru return ret; } +static void set_common_push_options(struct transport *transport, + const char *name, int flags) +{ + if (flags & TRANSPORT_PUSH_DRY_RUN) { + if (set_helper_option(transport, "dry-run", "true") != 0) + die("helper %s does not support dry-run", name); + } else if (flags & TRANSPORT_PUSH_CERT_ALWAYS) { + if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "true") != 0) + die("helper %s does not support --signed", name); + } else if (flags & TRANSPORT_PUSH_CERT_IF_ASKED) { + if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "if-asked") != 0) + die("helper %s does not support --signed=if-asked", name); + } +} + static int push_refs_with_push(struct transport *transport, struct ref *remote_refs, int flags) { @@@ -845,7 -831,14 +845,7 @@@ for_each_string_list_item(cas_option, &cas_options) set_helper_option(transport, "cas", cas_option->string); - - if (flags & TRANSPORT_PUSH_DRY_RUN) { - if (set_helper_option(transport, "dry-run", "true") != 0) - die("helper %s does not support dry-run", data->name); - } else if (flags & TRANSPORT_PUSH_CERT) { - if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "true") != 0) - die("helper %s does not support --signed", data->name); - } + set_common_push_options(transport, data->name, flags); strbuf_addch(&buf, '\n'); sendline(data, &buf); @@@ -866,7 -859,14 +866,7 @@@ static int push_refs_with_export(struc if (!data->refspecs) die("remote-helper doesn't support push; refspec needed"); - if (flags & TRANSPORT_PUSH_DRY_RUN) { - if (set_helper_option(transport, "dry-run", "true") != 0) - die("helper %s does not support dry-run", data->name); - } else if (flags & TRANSPORT_PUSH_CERT) { - if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "true") != 0) - die("helper %s does not support --signed", data->name); - } - + set_common_push_options(transport, data->name, flags); if (flags & TRANSPORT_PUSH_FORCE) { if (set_helper_option(transport, "force", "true") != 0) warning("helper %s does not support 'force'", data->name); @@@ -1043,6 -1043,8 +1043,8 @@@ int transport_helper_init(struct transp struct helper_data *data = xcalloc(1, sizeof(*data)); data->name = name; + transport_check_allowed(name); + if (getenv("GIT_TRANSPORT_HELPER_DEBUG")) debug = 1; diff --combined transport.c index 2d51348f3f,164a716053..863eb524f9 --- a/transport.c +++ b/transport.c @@@ -291,7 -291,7 +291,7 @@@ static int write_one_ref(const char *na strbuf_addstr(buf, name); if (safe_create_leading_directories(buf->buf) || - write_file(buf->buf, 0, "%s\n", oid_to_hex(oid))) + write_file_gently(buf->buf, "%s", oid_to_hex(oid))) return error("problems writing temporary file %s: %s", buf->buf, strerror(errno)); strbuf_setlen(buf, len); @@@ -476,6 -476,9 +476,6 @@@ static int set_git_option(struct git_tr die("transport: invalid depth option '%s'", value); } return 0; - } else if (!strcmp(name, TRANS_OPT_PUSH_CERT)) { - opts->push_cert = !!value; - return 0; } return 1; } @@@ -826,16 -829,10 +826,16 @@@ static int git_transport_push(struct tr args.progress = transport->progress; args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN); args.porcelain = !!(flags & TRANSPORT_PUSH_PORCELAIN); - args.push_cert = !!(flags & TRANSPORT_PUSH_CERT); args.atomic = !!(flags & TRANSPORT_PUSH_ATOMIC); args.url = transport->url; + if (flags & TRANSPORT_PUSH_CERT_ALWAYS) + args.push_cert = SEND_PACK_PUSH_CERT_ALWAYS; + else if (flags & TRANSPORT_PUSH_CERT_IF_ASKED) + args.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED; + else + args.push_cert = SEND_PACK_PUSH_CERT_NEVER; + ret = send_pack(&args, data->fd, data->conn, remote_refs, &data->extra_have); @@@ -915,6 -912,42 +915,42 @@@ static int external_specification_len(c return strchr(url, ':') - url; } + static const struct string_list *protocol_whitelist(void) + { + static int enabled = -1; + static struct string_list allowed = STRING_LIST_INIT_DUP; + + if (enabled < 0) { + const char *v = getenv("GIT_ALLOW_PROTOCOL"); + if (v) { + string_list_split(&allowed, v, ':', -1); + string_list_sort(&allowed); + enabled = 1; + } else { + enabled = 0; + } + } + + return enabled ? &allowed : NULL; + } + + int is_transport_allowed(const char *type) + { + const struct string_list *allowed = protocol_whitelist(); + return !allowed || string_list_has_string(allowed, type); + } + + void transport_check_allowed(const char *type) + { + if (!is_transport_allowed(type)) + die("transport '%s' not allowed", type); + } + + int transport_restrict_protocols(void) + { + return !!protocol_whitelist(); + } + struct transport *transport_get(struct remote *remote, const char *url) { const char *helper; @@@ -946,12 -979,14 +982,14 @@@ if (helper) { transport_helper_init(ret, helper); } else if (starts_with(url, "rsync:")) { + transport_check_allowed("rsync"); ret->get_refs_list = get_refs_via_rsync; ret->fetch = fetch_objs_via_rsync; ret->push = rsync_transport_push; ret->smart_options = NULL; } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) { struct bundle_transport_data *data = xcalloc(1, sizeof(*data)); + transport_check_allowed("file"); ret->data = data; ret->get_refs_list = get_refs_from_bundle; ret->fetch = fetch_refs_from_bundle; @@@ -963,7 -998,10 +1001,10 @@@ || starts_with(url, "ssh://") || starts_with(url, "git+ssh://") || starts_with(url, "ssh+git://")) { - /* These are builtin smart transports. */ + /* + * These are builtin smart transports; "allowed" transports + * will be checked individually in git_connect. + */ struct git_transport_data *data = xcalloc(1, sizeof(*data)); ret->data = data; ret->set_option = NULL; diff --combined transport.h index d682b77b9e,97707774e7..4336dd33eb --- a/transport.h +++ b/transport.h @@@ -12,6 -12,7 +12,6 @@@ struct git_transport_options unsigned check_self_contained_and_connected : 1; unsigned self_contained_and_connected : 1; unsigned update_shallow : 1; - unsigned push_cert : 1; int depth; const char *uploadpack; const char *receivepack; @@@ -123,9 -124,8 +123,9 @@@ struct transport #define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256 #define TRANSPORT_PUSH_NO_HOOK 512 #define TRANSPORT_PUSH_FOLLOW_TAGS 1024 -#define TRANSPORT_PUSH_CERT 2048 -#define TRANSPORT_PUSH_ATOMIC 4096 +#define TRANSPORT_PUSH_CERT_ALWAYS 2048 +#define TRANSPORT_PUSH_CERT_IF_ASKED 4096 +#define TRANSPORT_PUSH_ATOMIC 8192 #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) #define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x) @@@ -133,6 -133,24 +133,24 @@@ /* Returns a transport suitable for the url */ struct transport *transport_get(struct remote *, const char *); + /* + * Check whether a transport is allowed by the environment. Type should + * generally be the URL scheme, as described in Documentation/git.txt + */ + int is_transport_allowed(const char *type); + + /* + * Check whether a transport is allowed by the environment, + * and die otherwise. + */ + void transport_check_allowed(const char *type); + + /* + * Returns true if the user has attempted to turn on protocol + * restrictions at all. + */ + int transport_restrict_protocols(void); + /* Transport options which apply to git:// and scp-style URLs */ /* The program to use on the remote side to send a pack */