From: Junio C Hamano Date: Mon, 28 Sep 2015 22:28:26 +0000 (-0700) Subject: Sync with 2.3.10 X-Git-Tag: v2.4.10~1 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/6343e2f6f271cf344ea8e7384342502faecaf37c?ds=inline;hp=-c Sync with 2.3.10 --- 6343e2f6f271cf344ea8e7384342502faecaf37c diff --combined Documentation/git.txt index 97d9fb41b2,c06b923969..5826bd9771 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@@ -43,23 -43,10 +43,24 @@@ unreleased) version of Git, that is ava branch of the `git.git` repository. Documentation for older releases are available here: +* link:v2.4.9/git.html[documentation for release 2.4.9] + +* release notes for + 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], + link:RelNotes/2.4.6.txt[2.4.6], + link:RelNotes/2.4.5.txt[2.4.5], + link:RelNotes/2.4.4.txt[2.4.4], + link:RelNotes/2.4.3.txt[2.4.3], + link:RelNotes/2.4.2.txt[2.4.2], + 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], @@@ -941,7 -928,7 +942,7 @@@ for further details If this environment variable is set, then Git commands which need to acquire passwords or passphrases (e.g. for HTTP or IMAP authentication) will call this program with a suitable prompt as command-line argument - and read the password from its STDOUT. See also the 'core.askpass' + and read the password from its STDOUT. See also the 'core.askPass' option in linkgit:git-config[1]. 'GIT_TERMINAL_PROMPT':: @@@ -1059,6 -1046,33 +1060,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 b3e948e757,66b4fbf466..048ed53c2f --- a/builtin/blame.c +++ b/builtin/blame.c @@@ -26,14 -26,13 +26,14 @@@ #include "userdiff.h" #include "line-range.h" #include "line-log.h" +#include "dir.h" -static char blame_usage[] = N_("git blame [options] [rev-opts] [rev] [--] file"); +static char blame_usage[] = N_("git blame [] [] [] [--] "); static const char *blame_opt_usage[] = { blame_usage, "", - N_("[rev-opts] are documented in git-rev-list(1)"), + N_(" are documented in git-rev-list(1)"), NULL }; @@@ -973,7 -972,10 +973,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; @@@ -1119,7 -1121,9 +1122,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); } @@@ -2152,6 -2156,16 +2157,6 @@@ static void sanity_check_refcnt(struct } } -/* - * Used for the command line parsing; check if the path exists - * in the working tree. - */ -static int has_string_in_work_tree(const char *path) -{ - struct stat st; - return !lstat(path, &st); -} - static unsigned parse_score(const char *arg) { char *end; @@@ -2339,7 -2353,6 +2344,7 @@@ static struct commit *fake_working_tree if (strbuf_read(&buf, 0, 0) < 0) die_errno("failed to read from stdin"); } + convert_to_git(path, buf.buf, buf.len, &buf, 0); origin->file.ptr = buf.buf; origin->file.size = buf.len; pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1); @@@ -2647,14 -2660,14 +2652,14 @@@ parse_done if (argc < 2) usage_with_options(blame_opt_usage, options); path = add_prefix(prefix, argv[argc - 1]); - if (argc == 3 && !has_string_in_work_tree(path)) { /* (2b) */ + if (argc == 3 && !file_exists(path)) { /* (2b) */ path = add_prefix(prefix, argv[1]); argv[1] = argv[2]; } argv[argc - 1] = "--"; setup_work_tree(); - if (!has_string_in_work_tree(path)) + if (!file_exists(path)) die_errno("cannot stat path '%s'", path); } diff --combined builtin/merge-file.c index ea8093f676,04ae36a452..50d0bc873b --- a/builtin/merge-file.c +++ b/builtin/merge-file.c @@@ -5,7 -5,7 +5,7 @@@ #include "parse-options.h" static const char *const merge_file_usage[] = { - N_("git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"), + N_("git merge-file [] [-L [-L [-L ]]] "), NULL }; @@@ -42,7 -42,7 +42,7 @@@ int cmd_merge_file(int argc, const cha N_("for conflicts, use this marker size")), OPT__QUIET(&quiet, N_("do not warn about conflicts")), OPT_CALLBACK('L', NULL, names, N_("name"), - N_("set labels for file1/orig_file/file2"), &label_cb), + N_("set labels for file1/orig-file/file2"), &label_cb), OPT_END(), }; @@@ -75,7 -75,8 +75,8 @@@ names[i] = argv[i]; if (read_mmfile(mmfs + i, fname)) return -1; - if (buffer_is_binary(mmfs[i].ptr, mmfs[i].size)) + if (mmfs[i].size > MAX_XDIFF_SIZE || + buffer_is_binary(mmfs[i].ptr, mmfs[i].size)) return error("Cannot merge binary files: %s", argv[i]); } diff --combined builtin/rerere.c index 7afadd2ead,aab8f3b1f0..be55e0d2a7 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@@ -9,7 -9,7 +9,7 @@@ #include "pathspec.h" static const char * const rerere_usage[] = { - N_("git rerere [clear | forget path... | status | remaining | diff | gc]"), + N_("git rerere [clear | forget ... | status | remaining | diff | gc]"), NULL, }; @@@ -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,11 -41,11 +41,11 @@@ 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) @@@ -104,7 -105,8 +105,8 @@@ 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 usage_with_options(rerere_usage, options); diff --combined combine-diff.c index d777e92aa0,284bec6ad5..5cae5fbd62 --- a/combine-diff.c +++ b/combine-diff.c @@@ -419,8 -419,10 +419,10 @@@ static void combine_diff(const unsigne state.num_parent = num_parent; state.n = n; - xdi_diff_outf(&parent_file, result_file, consume_line, &state, - &xpp, &xecfg); + if (xdi_diff_outf(&parent_file, result_file, consume_line, &state, + &xpp, &xecfg)) + die("unable to generate combined diff for %s", + sha1_to_hex(parent)); free(parent_file.ptr); /* Assign line numbers for this parent. @@@ -730,7 -732,7 +732,7 @@@ static void dump_sline(struct sline *sl const char *c_func = diff_get_color(use_color, DIFF_FUNCINFO); const char *c_new = diff_get_color(use_color, DIFF_FILE_NEW); const char *c_old = diff_get_color(use_color, DIFF_FILE_OLD); - const char *c_plain = diff_get_color(use_color, DIFF_PLAIN); + const char *c_context = diff_get_color(use_color, DIFF_CONTEXT); const char *c_reset = diff_get_color(use_color, DIFF_RESET); if (result_deleted) @@@ -793,7 -795,7 +795,7 @@@ } if (comment_end) printf("%s%s %s%s", c_reset, - c_plain, c_reset, + c_context, c_reset, c_func); for (i = 0; i < comment_end; i++) putchar(hunk_comment[i]); @@@ -828,7 -830,7 +830,7 @@@ */ if (!context) continue; - fputs(c_plain, stdout); + fputs(c_context, stdout); } else fputs(c_new, stdout); diff --combined connect.c index c0144d859a,bd4b50ea15..27a706f766 --- a/connect.c +++ b/connect.c @@@ -9,6 -9,7 +9,7 @@@ #include "url.h" #include "string-list.h" #include "sha1-array.h" + #include "transport.h" static char *server_capabilities; static const char *parse_feature_value(const char *, const char *, int *); @@@ -694,6 -695,8 +695,8 @@@ struct child_process *git_connect(int f else target_host = xstrdup(hostandport); + transport_check_allowed("git"); + /* These underlying connection commands die() if they * cannot connect. */ @@@ -724,9 -727,10 +727,10 @@@ conn->in = conn->out = -1; if (protocol == PROTO_SSH) { const char *ssh; - int putty; + int putty, tortoiseplink = 0; char *ssh_host = hostandport; const char *port = NULL; + transport_check_allowed("ssh"); get_host_and_port(&ssh_host, &port); if (!port) @@@ -741,46 -745,34 +745,47 @@@ free(hostandport); free(path); + free(conn); return NULL; + } + + ssh = getenv("GIT_SSH_COMMAND"); + if (ssh) { + conn->use_shell = 1; + putty = 0; } else { - ssh = getenv("GIT_SSH_COMMAND"); - if (ssh) { - conn->use_shell = 1; - putty = 0; - } else { - ssh = getenv("GIT_SSH"); - if (!ssh) - ssh = "ssh"; - putty = !!strcasestr(ssh, "plink"); - } - - argv_array_push(&conn->args, ssh); - if (putty && !strcasestr(ssh, "tortoiseplink")) - argv_array_push(&conn->args, "-batch"); - if (port) { - /* P is for PuTTY, p is for OpenSSH */ - argv_array_push(&conn->args, putty ? "-P" : "-p"); - argv_array_push(&conn->args, port); - } - argv_array_push(&conn->args, ssh_host); + const char *base; + char *ssh_dup; + + ssh = getenv("GIT_SSH"); + if (!ssh) + ssh = "ssh"; + + ssh_dup = xstrdup(ssh); + base = basename(ssh_dup); + + tortoiseplink = !strcasecmp(base, "tortoiseplink") || + !strcasecmp(base, "tortoiseplink.exe"); + putty = !strcasecmp(base, "plink") || + !strcasecmp(base, "plink.exe") || tortoiseplink; + + free(ssh_dup); + } + + argv_array_push(&conn->args, ssh); + if (tortoiseplink) + argv_array_push(&conn->args, "-batch"); + if (port) { + /* P is for PuTTY, p is for OpenSSH */ + argv_array_push(&conn->args, putty ? "-P" : "-p"); + argv_array_push(&conn->args, port); } + argv_array_push(&conn->args, ssh_host); } else { /* remove repo-local variables from the environment */ conn->env = local_repo_env; conn->use_shell = 1; + transport_check_allowed("file"); } argv_array_push(&conn->args, cmd.buf); diff --combined diff.c index 100773f5b1,6bbf28bff2..f62b7f73d8 --- a/diff.c +++ b/diff.c @@@ -42,7 -42,7 +42,7 @@@ static long diff_algorithm static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, - GIT_COLOR_NORMAL, /* PLAIN */ + GIT_COLOR_NORMAL, /* CONTEXT */ GIT_COLOR_BOLD, /* METAINFO */ GIT_COLOR_CYAN, /* FRAGINFO */ GIT_COLOR_RED, /* OLD */ @@@ -54,8 -54,8 +54,8 @@@ static int parse_diff_color_slot(const char *var) { - if (!strcasecmp(var, "plain")) - return DIFF_PLAIN; + if (!strcasecmp(var, "context") || !strcasecmp(var, "plain")) + return DIFF_CONTEXT; if (!strcasecmp(var, "meta")) return DIFF_METAINFO; if (!strcasecmp(var, "frag")) @@@ -501,7 -501,7 +501,7 @@@ static void emit_add_line(const char *r static void emit_hunk_header(struct emit_callback *ecbdata, const char *line, int len) { - const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN); + const char *context = diff_get_color(ecbdata->color_diff, DIFF_CONTEXT); const char *frag = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO); const char *func = diff_get_color(ecbdata->color_diff, DIFF_FUNCINFO); const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); @@@ -518,7 -518,7 +518,7 @@@ if (len < 10 || memcmp(line, atat, 2) || !(ep = memmem(line + 2, len - 2, atat, 2))) { - emit_line(ecbdata->opt, plain, reset, line, len); + emit_line(ecbdata->opt, context, reset, line, len); return; } ep += 2; /* skip over @@ */ @@@ -540,7 -540,7 +540,7 @@@ if (*ep != ' ' && *ep != '\t') break; if (ep != cp) { - strbuf_addstr(&msgbuf, plain); + strbuf_addstr(&msgbuf, context); strbuf_add(&msgbuf, cp, ep - cp); strbuf_addstr(&msgbuf, reset); } @@@ -623,10 -623,10 +623,10 @@@ static void emit_rewrite_lines(struct e data += len; } if (!endp) { - const char *plain = diff_get_color(ecb->color_diff, - DIFF_PLAIN); + const char *context = diff_get_color(ecb->color_diff, + DIFF_CONTEXT); putc('\n', ecb->opt->file); - emit_line_0(ecb->opt, plain, reset, '\\', + emit_line_0(ecb->opt, context, reset, '\\', nneof, strlen(nneof)); } } @@@ -1002,8 -1002,9 +1002,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 + @@@ -1086,7 -1087,7 +1087,7 @@@ static void init_diff_words_data(struc struct diff_words_style *st = ecbdata->diff_words->style; st->old.color = diff_get_color_opt(o, DIFF_FILE_OLD); st->new.color = diff_get_color_opt(o, DIFF_FILE_NEW); - st->ctx.color = diff_get_color_opt(o, DIFF_PLAIN); + st->ctx.color = diff_get_color_opt(o, DIFF_CONTEXT); } } @@@ -1162,7 -1163,7 +1163,7 @@@ static void fn_out_consume(void *priv, { struct emit_callback *ecbdata = priv; const char *meta = diff_get_color(ecbdata->color_diff, DIFF_METAINFO); - const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN); + const char *context = diff_get_color(ecbdata->color_diff, DIFF_CONTEXT); const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); struct diff_options *o = ecbdata->opt; const char *line_prefix = diff_line_prefix(o); @@@ -1233,7 -1234,7 +1234,7 @@@ } diff_words_flush(ecbdata); if (ecbdata->diff_words->type == DIFF_WORDS_PORCELAIN) { - emit_line(ecbdata->opt, plain, reset, line, len); + emit_line(ecbdata->opt, context, reset, line, len); fputs("~\n", ecbdata->opt->file); } else { /* @@@ -1245,7 -1246,7 +1246,7 @@@ line++; len--; } - emit_line(ecbdata->opt, plain, reset, line, len); + emit_line(ecbdata->opt, context, reset, line, len); } return; } @@@ -1253,7 -1254,7 +1254,7 @@@ if (line[0] != '+') { const char *color = diff_get_color(ecbdata->color_diff, - line[0] == '-' ? DIFF_FILE_OLD : DIFF_PLAIN); + line[0] == '-' ? DIFF_FILE_OLD : DIFF_CONTEXT); ecbdata->lno_in_preimage++; if (line[0] == ' ') ecbdata->lno_in_postimage++; @@@ -2400,8 -2401,9 +2401,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) @@@ -2478,8 -2480,9 +2480,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); @@@ -2525,8 -2528,9 +2528,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; @@@ -4425,8 -4429,10 +4429,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 9a7e0892e4,00e3fc80e8..9448c50f0f --- a/http.c +++ b/http.c @@@ -8,7 -8,7 +8,8 @@@ #include "credential.h" #include "version.h" #include "pkt-line.h" +#include "gettext.h" + #include "transport.h" int active_requests; int http_is_verbose; @@@ -72,8 -72,6 +73,8 @@@ static struct curl_slist *no_pragma_hea static struct active_request_slot *active_queue_head; +static char *cached_accept_language; + size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_) { size_t size = eltsize * nmemb; @@@ -120,37 -118,6 +121,37 @@@ size_t fwrite_null(char *ptr, size_t el return eltsize * nmemb; } +static void closedown_active_slot(struct active_request_slot *slot) +{ + active_requests--; + slot->in_use = 0; +} + +static void finish_active_slot(struct active_request_slot *slot) +{ + closedown_active_slot(slot); + curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code); + + if (slot->finished != NULL) + (*slot->finished) = 1; + + /* Store slot results so they can be read after the slot is reused */ + if (slot->results != NULL) { + slot->results->curl_result = slot->curl_result; + slot->results->http_code = slot->http_code; +#if LIBCURL_VERSION_NUM >= 0x070a08 + curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL, + &slot->results->auth_avail); +#else + slot->results->auth_avail = 0; +#endif + } + + /* Run callback if appropriate */ + if (slot->callback_func != NULL) + slot->callback_func(slot->callback_data); +} + #ifdef USE_CURL_MULTI static void process_curl_messages(void) { @@@ -337,6 -304,7 +338,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"); @@@ -384,11 -352,27 +386,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); @@@ -406,10 -390,8 +424,10 @@@ if (curl_http_proxy) { curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy); - curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); } +#if LIBCURL_VERSION_NUM >= 0x070a07 + curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); +#endif set_curl_keepalive(result); @@@ -554,9 -536,6 +572,9 @@@ void http_cleanup(void cert_auth.password = NULL; } ssl_cert_password_required = 0; + + free(cached_accept_language); + cached_accept_language = NULL; } struct active_request_slot *get_active_slot(void) @@@ -775,6 -754,12 +793,6 @@@ void run_active_slot(struct active_requ #endif } -static void closedown_active_slot(struct active_request_slot *slot) -{ - active_requests--; - slot->in_use = 0; -} - static void release_active_slot(struct active_request_slot *slot) { closedown_active_slot(slot); @@@ -791,6 -776,31 +809,6 @@@ #endif } -void finish_active_slot(struct active_request_slot *slot) -{ - closedown_active_slot(slot); - curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code); - - if (slot->finished != NULL) - (*slot->finished) = 1; - - /* Store slot results so they can be read after the slot is reused */ - if (slot->results != NULL) { - slot->results->curl_result = slot->curl_result; - slot->results->http_code = slot->http_code; -#if LIBCURL_VERSION_NUM >= 0x070a08 - curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL, - &slot->results->auth_avail); -#else - slot->results->auth_avail = 0; -#endif - } - - /* Run callback if appropriate */ - if (slot->callback_func != NULL) - slot->callback_func(slot->callback_data); -} - void finish_all_active_slots(void) { struct active_request_slot *slot = active_queue_head; @@@ -853,7 -863,7 +871,7 @@@ char *get_remote_object_url(const char return strbuf_detach(&buf, NULL); } -int handle_curl_result(struct slot_results *results) +static int handle_curl_result(struct slot_results *results) { /* * If we see a failing http code with CURLE_OK, we have turned off @@@ -1003,116 -1013,6 +1021,116 @@@ static void extract_content_type(struc strbuf_addstr(charset, "ISO-8859-1"); } +static void write_accept_language(struct strbuf *buf) +{ + /* + * MAX_DECIMAL_PLACES must not be larger than 3. If it is larger than + * that, q-value will be smaller than 0.001, the minimum q-value the + * HTTP specification allows. See + * http://tools.ietf.org/html/rfc7231#section-5.3.1 for q-value. + */ + const int MAX_DECIMAL_PLACES = 3; + const int MAX_LANGUAGE_TAGS = 1000; + const int MAX_ACCEPT_LANGUAGE_HEADER_SIZE = 4000; + char **language_tags = NULL; + int num_langs = 0; + const char *s = get_preferred_languages(); + int i; + struct strbuf tag = STRBUF_INIT; + + /* Don't add Accept-Language header if no language is preferred. */ + if (!s) + return; + + /* + * Split the colon-separated string of preferred languages into + * language_tags array. + */ + do { + /* collect language tag */ + for (; *s && (isalnum(*s) || *s == '_'); s++) + strbuf_addch(&tag, *s == '_' ? '-' : *s); + + /* skip .codeset, @modifier and any other unnecessary parts */ + while (*s && *s != ':') + s++; + + if (tag.len) { + num_langs++; + REALLOC_ARRAY(language_tags, num_langs); + language_tags[num_langs - 1] = strbuf_detach(&tag, NULL); + if (num_langs >= MAX_LANGUAGE_TAGS - 1) /* -1 for '*' */ + break; + } + } while (*s++); + + /* write Accept-Language header into buf */ + if (num_langs) { + int last_buf_len = 0; + int max_q; + int decimal_places; + char q_format[32]; + + /* add '*' */ + REALLOC_ARRAY(language_tags, num_langs + 1); + language_tags[num_langs++] = "*"; /* it's OK; this won't be freed */ + + /* compute decimal_places */ + for (max_q = 1, decimal_places = 0; + max_q < num_langs && decimal_places <= MAX_DECIMAL_PLACES; + decimal_places++, max_q *= 10) + ; + + sprintf(q_format, ";q=0.%%0%dd", decimal_places); + + strbuf_addstr(buf, "Accept-Language: "); + + for (i = 0; i < num_langs; i++) { + if (i > 0) + strbuf_addstr(buf, ", "); + + strbuf_addstr(buf, language_tags[i]); + + if (i > 0) + strbuf_addf(buf, q_format, max_q - i); + + if (buf->len > MAX_ACCEPT_LANGUAGE_HEADER_SIZE) { + strbuf_remove(buf, last_buf_len, buf->len - last_buf_len); + break; + } + + last_buf_len = buf->len; + } + } + + /* free language tags -- last one is a static '*' */ + for (i = 0; i < num_langs - 1; i++) + free(language_tags[i]); + free(language_tags); +} + +/* + * Get an Accept-Language header which indicates user's preferred languages. + * + * Examples: + * LANGUAGE= -> "" + * LANGUAGE=ko:en -> "Accept-Language: ko, en; q=0.9, *; q=0.1" + * LANGUAGE=ko_KR.UTF-8:sr@latin -> "Accept-Language: ko-KR, sr; q=0.9, *; q=0.1" + * LANGUAGE=ko LANG=en_US.UTF-8 -> "Accept-Language: ko, *; q=0.1" + * LANGUAGE= LANG=en_US.UTF-8 -> "Accept-Language: en-US, *; q=0.1" + * LANGUAGE= LANG=C -> "" + */ +static const char *get_accept_language(void) +{ + if (!cached_accept_language) { + struct strbuf buf = STRBUF_INIT; + write_accept_language(&buf); + if (buf.len > 0) + cached_accept_language = strbuf_detach(&buf, NULL); + } + + return cached_accept_language; +} /* http_request() targets */ #define HTTP_REQUEST_STRBUF 0 @@@ -1126,7 -1026,6 +1144,7 @@@ static int http_request(const char *url struct slot_results results; struct curl_slist *headers = NULL; struct strbuf buf = STRBUF_INIT; + const char *accept_language; int ret; slot = get_active_slot(); @@@ -1152,11 -1051,6 +1170,11 @@@ fwrite_buffer); } + accept_language = get_accept_language(); + + if (accept_language) + headers = curl_slist_append(headers, accept_language); + strbuf_addstr(&buf, "Pragma:"); if (options && options->no_cache) strbuf_addstr(&buf, " no-cache"); @@@ -1462,7 -1356,6 +1480,7 @@@ void release_http_pack_request(struct h } preq->slot = NULL; free(preq->url); + free(preq); } int finish_http_pack_request(struct http_pack_request *preq) diff --combined line-log.c index c12c69f05a,d4e29a574f..626b22cc31 --- a/line-log.c +++ b/line-log.c @@@ -237,7 -237,7 +237,7 @@@ static void diff_ranges_release(struct range_set_release(&diff->target); } -void line_log_data_init(struct line_log_data *r) +static void line_log_data_init(struct line_log_data *r) { memset(r, 0, sizeof(struct line_log_data)); range_set_init(&r->ranges, 0); @@@ -325,7 -325,7 +325,7 @@@ static int collect_diff_cb(long start_a return 0; } - static void collect_diff(mmfile_t *parent, mmfile_t *target, struct diff_ranges *out) + static int collect_diff(mmfile_t *parent, mmfile_t *target, struct diff_ranges *out) { struct collect_diff_cbdata cbdata = {NULL}; xpparam_t xpp; @@@ -340,7 -340,7 +340,7 @@@ xecfg.hunk_func = collect_diff_cb; memset(&ecb, 0, sizeof(ecb)); ecb.priv = &cbdata; - xdi_diff(parent, target, &xpp, &xecfg, &ecb); + return xdi_diff(parent, target, &xpp, &xecfg, &ecb); } /* @@@ -893,7 -893,7 +893,7 @@@ static void dump_diff_hacky_one(struct const char *c_meta = diff_get_color(opt->use_color, DIFF_METAINFO); const char *c_old = diff_get_color(opt->use_color, DIFF_FILE_OLD); const char *c_new = diff_get_color(opt->use_color, DIFF_FILE_NEW); - const char *c_plain = diff_get_color(opt->use_color, DIFF_PLAIN); + const char *c_context = diff_get_color(opt->use_color, DIFF_CONTEXT); if (!pair || !diff) return; @@@ -957,7 -957,7 +957,7 @@@ int k; for (; t_cur < diff->target.ranges[j].start; t_cur++) print_line(prefix, ' ', t_cur, t_ends, pair->two->data, - c_plain, c_reset); + c_context, c_reset); for (k = diff->parent.ranges[j].start; k < diff->parent.ranges[j].end; k++) print_line(prefix, '-', k, p_ends, pair->one->data, c_old, c_reset); @@@ -968,7 -968,7 +968,7 @@@ } for (; t_cur < t_end; t_cur++) print_line(prefix, ' ', t_cur, t_ends, pair->two->data, - c_plain, c_reset); + c_context, c_reset); } free(p_ends); @@@ -1030,7 -1030,8 +1030,8 @@@ static int process_diff_filepair(struc } diff_ranges_init(&diff); - collect_diff(&file_parent, &file_target, &diff); + if (collect_diff(&file_parent, &file_target, &diff)) + die("unable to generate diff for %s", pair->one->path); /* NEEDSWORK should apply some heuristics to prevent mismatches */ free(rg->path); @@@ -1099,7 -1100,6 +1100,7 @@@ static int process_all_files(struct lin rg->pair = diff_filepair_dup(queue->queue[i]); memcpy(&rg->diff, pairdiff, sizeof(struct diff_ranges)); } + free(pairdiff); } return changed; diff --combined transport-helper.c index 5d99a6bc2e,0b5362c268..b486441c48 --- a/transport-helper.c +++ b/transport-helper.c @@@ -97,8 -97,6 +97,8 @@@ static void do_take_over(struct transpo free(data); } +static void standard_options(struct transport *t); + static struct child_process *get_helper(struct transport *transport) { struct helper_data *data = transport->data; @@@ -213,7 -211,6 +213,7 @@@ strbuf_release(&buf); if (debug) fprintf(stderr, "Debug: Capabilities complete.\n"); + standard_options(transport); return data->helper; } @@@ -341,6 -338,17 +341,6 @@@ static int fetch_with_fetch(struct tran int i; struct strbuf buf = STRBUF_INIT; - standard_options(transport); - if (data->check_connectivity && - data->transport_options.check_self_contained_and_connected) - set_helper_option(transport, "check-connectivity", "true"); - - if (transport->cloning) - set_helper_option(transport, "cloning", "true"); - - if (data->transport_options.update_shallow) - set_helper_option(transport, "update-shallow", "true"); - for (i = 0; i < nr_heads; i++) { const struct ref *posn = to_fetch[i]; if (posn->status & REF_STATUS_UPTODATE) @@@ -614,16 -622,6 +614,16 @@@ static int fetch(struct transport *tran if (!count) return 0; + if (data->check_connectivity && + data->transport_options.check_self_contained_and_connected) + set_helper_option(transport, "check-connectivity", "true"); + + if (transport->cloning) + set_helper_option(transport, "cloning", "true"); + + if (data->transport_options.update_shallow) + set_helper_option(transport, "update-shallow", "true"); + if (data->fetch) return fetch_with_fetch(transport, nr_heads, to_fetch); @@@ -828,6 -826,7 +828,6 @@@ static int push_refs_with_push(struct t return 0; } - standard_options(transport); for_each_string_list_item(cas_option, &cas_options) set_helper_option(transport, "cas", cas_option->string); @@@ -1039,6 -1038,8 +1039,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 eca9b8c817,647d2c2afa..198502d0ba --- a/transport.c +++ b/transport.c @@@ -730,10 -730,6 +730,10 @@@ static int print_one_push_status(struc ref->deletion ? NULL : ref->peer_ref, "remote failed to report status", porcelain); break; + case REF_STATUS_ATOMIC_PUSH_FAILED: + print_ref_status('!', "[rejected]", ref, ref->peer_ref, + "atomic push failed", porcelain); + break; case REF_STATUS_OK: print_ok_ref_status(ref, porcelain); break; @@@ -832,7 -828,6 +832,7 @@@ static int git_transport_push(struct tr 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; ret = send_pack(&args, data->fd, data->conn, remote_refs, @@@ -914,6 -909,42 +914,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; @@@ -945,12 -976,14 +981,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; @@@ -962,7 -995,10 +1000,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 18d2cf8275,ed84da2aa4..97707774e7 --- a/transport.h +++ b/transport.h @@@ -125,7 -125,6 +125,7 @@@ struct transport #define TRANSPORT_PUSH_NO_HOOK 512 #define TRANSPORT_PUSH_FOLLOW_TAGS 1024 #define TRANSPORT_PUSH_CERT 2048 +#define TRANSPORT_PUSH_ATOMIC 4096 #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) #define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x) @@@ -133,6 -132,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 */