char *git_prompt(const char *prompt, int flags) { char *r = NULL; if (flags & PROMPT_ASKPASS) { const char *askpass; askpass = getenv("GIT_ASKPASS"); if (!askpass) askpass = askpass_program; if (!askpass) askpass = getenv("SSH_ASKPASS"); if (askpass && *askpass) r = do_askpass(askpass, prompt); } if (!r) { const char *err; if (git_env_bool("GIT_TERMINAL_PROMPT", 1)) { r = git_terminal_prompt(prompt, flags & PROMPT_ECHO); err = strerror(errno); } else { err = "terminal prompts disabled"; } if (!r) { /* prompts already contain ": " at the end */ die("could not read %s%s", prompt, err); } } return r; }
int limit_pathspec_to_literal(void) { static int flag = -1; if (flag < 0) flag = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0); return flag; }
/* * Enables the cache. Note that the cache is read-only, changes to * the working directory are NOT reflected in the cache while enabled. */ int fscache_enable(size_t initial_size) { int fscache; struct fscache *cache; int result = 0; /* allow the cache to be disabled entirely */ fscache = git_env_bool("GIT_TEST_FSCACHE", -1); if (fscache != -1) core_fscache = fscache; if (!core_fscache) return 0; /* * refcount the global fscache initialization so that the * opendir and lstat function pointers are redirected if * any threads are using the fscache. */ EnterCriticalSection(&fscache_cs); if (!initialized) { if (!dwTlsIndex) { dwTlsIndex = TlsAlloc(); if (dwTlsIndex == TLS_OUT_OF_INDEXES) return 0; } /* redirect opendir and lstat to the fscache implementations */ opendir = fscache_opendir; lstat = fscache_lstat; } initialized++; LeaveCriticalSection(&fscache_cs); /* refcount the thread specific initialization */ cache = fscache_getcache(); if (cache) { cache->enabled++; } else { cache = (struct fscache *)xcalloc(1, sizeof(*cache)); cache->enabled = 1; /* * avoid having to rehash by leaving room for the parent dirs. * '4' was determined empirically by testing several repos */ hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, initial_size * 4); mem_pool_init(&cache->mem_pool, 0); if (!TlsSetValue(dwTlsIndex, cache)) BUG("TlsSetValue error"); } trace_printf_key(&trace_fscache, "fscache: enable\n"); return result; }
int is_transport_allowed(const char *type, int from_user) { const struct string_list *whitelist = protocol_whitelist(); if (whitelist) return string_list_has_string(whitelist, type); switch (get_protocol_config(type)) { case PROTOCOL_ALLOW_ALWAYS: return 1; case PROTOCOL_ALLOW_NEVER: return 0; case PROTOCOL_ALLOW_USER_ONLY: if (from_user < 0) from_user = git_env_bool("GIT_PROTOCOL_FROM_USER", 1); return from_user; } BUG("invalid protocol_allow_config type"); }
static int use_builtin_stash(void) { struct child_process cp = CHILD_PROCESS_INIT; struct strbuf out = STRBUF_INIT; int ret, env = git_env_bool("GIT_TEST_STASH_USE_BUILTIN", -1); if (env != -1) return env; argv_array_pushl(&cp.args, "config", "--bool", "stash.usebuiltin", NULL); cp.git_cmd = 1; if (capture_command(&cp, &out, 6)) { strbuf_release(&out); return 1; } strbuf_trim(&out); ret = !strcmp("true", out.buf); strbuf_release(&out); return ret; }
int git_config_system(void) { return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0); }
static int git_attr_system(void) { return !git_env_bool("GIT_ATTR_NOSYSTEM", 0); }
/* * We cannot decide in this function whether we are in the work tree or * not, since the config can only be read _after_ this function was called. */ static const char *setup_git_directory_gently_1(int *nongit_ok) { const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT); struct string_list ceiling_dirs = STRING_LIST_INIT_DUP; static struct strbuf cwd = STRBUF_INIT; const char *gitdirenv, *ret; char *gitfile; int offset, offset_parent, ceil_offset = -1; dev_t current_device = 0; int one_filesystem = 1; /* * We may have read an incomplete configuration before * setting-up the git directory. If so, clear the cache so * that the next queries to the configuration reload complete * configuration (including the per-repo config file that we * ignored previously). */ git_config_clear(); /* * Let's assume that we are in a git repository. * If it turns out later that we are somewhere else, the value will be * updated accordingly. */ if (nongit_ok) *nongit_ok = 0; if (strbuf_getcwd(&cwd)) die_errno("Unable to read current working directory"); offset = cwd.len; /* * If GIT_DIR is set explicitly, we're not going * to do any discovery, but we still do repository * validation. */ gitdirenv = getenv(GIT_DIR_ENVIRONMENT); if (gitdirenv) return setup_explicit_git_dir(gitdirenv, &cwd, nongit_ok); if (env_ceiling_dirs) { int empty_entry_found = 0; string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1); filter_string_list(&ceiling_dirs, 0, canonicalize_ceiling_entry, &empty_entry_found); ceil_offset = longest_ancestor_length(cwd.buf, &ceiling_dirs); string_list_clear(&ceiling_dirs, 0); } if (ceil_offset < 0 && has_dos_drive_prefix(cwd.buf)) ceil_offset = 1; /* * Test in the following order (relative to the cwd): * - .git (file containing "gitdir: <path>") * - .git/ * - ./ (bare) * - ../.git * - ../.git/ * - ../ (bare) * - ../../.git/ * etc. */ one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0); if (one_filesystem) current_device = get_device_or_die(".", NULL, 0); for (;;) { gitfile = (char*)read_gitfile(DEFAULT_GIT_DIR_ENVIRONMENT); if (gitfile) gitdirenv = gitfile = xstrdup(gitfile); else { if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT)) gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT; } if (gitdirenv) { ret = setup_discovered_git_dir(gitdirenv, &cwd, offset, nongit_ok); free(gitfile); return ret; } free(gitfile); if (is_git_directory(".")) return setup_bare_git_dir(&cwd, offset, nongit_ok); offset_parent = offset; while (--offset_parent > ceil_offset && cwd.buf[offset_parent] != '/'); if (offset_parent <= ceil_offset) return setup_nongit(cwd.buf, nongit_ok); if (one_filesystem) { dev_t parent_device = get_device_or_die("..", cwd.buf, offset); if (parent_device != current_device) { if (nongit_ok) { if (chdir(cwd.buf)) die_errno("Cannot come back to cwd"); *nongit_ok = 1; return NULL; } strbuf_setlen(&cwd, offset); die("Not a git repository (or any parent up to mount point %s)\n" "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", cwd.buf); } } if (chdir("..")) { strbuf_setlen(&cwd, offset); die_errno("Cannot change to '%s/..'", cwd.buf); } offset = offset_parent; } }
static const char *setup_explicit_git_dir(const char *gitdirenv, struct strbuf *cwd, int *nongit_ok) { const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT); const char *worktree; char *gitfile; int offset; if (PATH_MAX - 40 < strlen(gitdirenv)) die("'$%s' too big", GIT_DIR_ENVIRONMENT); gitfile = (char*)read_gitfile(gitdirenv); if (gitfile) { gitfile = xstrdup(gitfile); gitdirenv = gitfile; } if (!is_git_directory(gitdirenv)) { if (nongit_ok) { *nongit_ok = 1; free(gitfile); return NULL; } die("Not a git repository: '%s'", gitdirenv); } if (check_repository_format_gently(gitdirenv, nongit_ok)) { free(gitfile); return NULL; } /* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */ if (work_tree_env) set_git_work_tree(work_tree_env); else if (is_bare_repository_cfg > 0) { if (git_work_tree_cfg) { /* #22.2, #30 */ warning("core.bare and core.worktree do not make sense"); work_tree_config_is_bogus = 1; } /* #18, #26 */ set_git_dir(gitdirenv); free(gitfile); return NULL; } else if (git_work_tree_cfg) { /* #6, #14 */ if (is_absolute_path(git_work_tree_cfg)) set_git_work_tree(git_work_tree_cfg); else { char *core_worktree; if (chdir(gitdirenv)) die_errno("Could not chdir to '%s'", gitdirenv); if (chdir(git_work_tree_cfg)) die_errno("Could not chdir to '%s'", git_work_tree_cfg); core_worktree = xgetcwd(); if (chdir(cwd->buf)) die_errno("Could not come back to cwd"); set_git_work_tree(core_worktree); free(core_worktree); } } else if (!git_env_bool(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, 1)) { /* #16d */ set_git_dir(gitdirenv); free(gitfile); return NULL; } else /* #2, #10 */ set_git_work_tree("."); /* set_git_work_tree() must have been called by now */ worktree = get_git_work_tree(); /* both get_git_work_tree() and cwd are already normalized */ if (!strcmp(cwd->buf, worktree)) { /* cwd == worktree */ set_git_dir(gitdirenv); free(gitfile); return NULL; } offset = dir_inside_of(cwd->buf, worktree); if (offset >= 0) { /* cwd inside worktree? */ set_git_dir(real_path(gitdirenv)); if (chdir(worktree)) die_errno("Could not chdir to '%s'", worktree); strbuf_addch(cwd, '/'); free(gitfile); return cwd->buf + offset; } /* cwd outside worktree */ set_git_dir(gitdirenv); free(gitfile); return NULL; }
static struct discovery *discover_refs(const char *service, int for_push) { struct strbuf exp = STRBUF_INIT; struct strbuf type = STRBUF_INIT; struct strbuf charset = STRBUF_INIT; struct strbuf buffer = STRBUF_INIT; struct strbuf refs_url = STRBUF_INIT; struct strbuf effective_url = STRBUF_INIT; struct discovery *last = last_discovery; int http_ret, maybe_smart = 0; struct http_get_options options; if (last && !strcmp(service, last->service)) return last; free_discovery(last); strbuf_addf(&refs_url, "%sinfo/refs", url.buf); if ((starts_with(url.buf, "http://") || starts_with(url.buf, "https://")) && git_env_bool("GIT_SMART_HTTP", 1)) { maybe_smart = 1; if (!strchr(url.buf, '?')) strbuf_addch(&refs_url, '?'); else strbuf_addch(&refs_url, '&'); strbuf_addf(&refs_url, "service=%s", service); } memset(&options, 0, sizeof(options)); options.content_type = &type; options.charset = &charset; options.effective_url = &effective_url; options.base_url = &url; options.no_cache = 1; options.keep_error = 1; http_ret = http_get_strbuf(refs_url.buf, &buffer, &options); switch (http_ret) { case HTTP_OK: break; case HTTP_MISSING_TARGET: show_http_message(&type, &charset, &buffer); die("repository '%s' not found", url.buf); case HTTP_NOAUTH: show_http_message(&type, &charset, &buffer); die("Authentication failed for '%s'", url.buf); default: show_http_message(&type, &charset, &buffer); die("unable to access '%s': %s", url.buf, curl_errorstr); } last= xcalloc(1, sizeof(*last_discovery)); last->service = service; last->buf_alloc = strbuf_detach(&buffer, &last->len); last->buf = last->buf_alloc; strbuf_addf(&exp, "application/x-%s-advertisement", service); if (maybe_smart && (5 <= last->len && last->buf[4] == '#') && !strbuf_cmp(&exp, &type)) { char *line; /* * smart HTTP response; validate that the service * pkt-line matches our request. */ line = packet_read_line_buf(&last->buf, &last->len, NULL); strbuf_reset(&exp); strbuf_addf(&exp, "# service=%s", service); if (strcmp(line, exp.buf)) die("invalid server response; got '%s'", line); strbuf_release(&exp); /* The header can include additional metadata lines, up * until a packet flush marker. Ignore these now, but * in the future we might start to scan them. */ while (packet_read_line_buf(&last->buf, &last->len, NULL)) ; last->proto_git = 1; } if (last->proto_git) last->refs = parse_git_refs(last, for_push); else last->refs = parse_info_refs(last); strbuf_release(&refs_url); strbuf_release(&exp); strbuf_release(&type); strbuf_release(&charset); strbuf_release(&effective_url); strbuf_release(&buffer); last_discovery = last; return last; }
static struct discovery *discover_refs(const char *service, int for_push) { struct strbuf exp = STRBUF_INIT; struct strbuf type = STRBUF_INIT; struct strbuf charset = STRBUF_INIT; struct strbuf buffer = STRBUF_INIT; struct strbuf refs_url = STRBUF_INIT; struct strbuf effective_url = STRBUF_INIT; struct strbuf protocol_header = STRBUF_INIT; struct string_list extra_headers = STRING_LIST_INIT_DUP; struct discovery *last = last_discovery; int http_ret, maybe_smart = 0; struct http_get_options http_options; enum protocol_version version = get_protocol_version_config(); if (last && !strcmp(service, last->service)) return last; free_discovery(last); strbuf_addf(&refs_url, "%sinfo/refs", url.buf); if ((starts_with(url.buf, "http://") || starts_with(url.buf, "https://")) && git_env_bool("GIT_SMART_HTTP", 1)) { maybe_smart = 1; if (!strchr(url.buf, '?')) strbuf_addch(&refs_url, '?'); else strbuf_addch(&refs_url, '&'); strbuf_addf(&refs_url, "service=%s", service); } /* * NEEDSWORK: If we are trying to use protocol v2 and we are planning * to perform a push, then fallback to v0 since the client doesn't know * how to push yet using v2. */ if (version == protocol_v2 && !strcmp("git-receive-pack", service)) version = protocol_v0; /* Add the extra Git-Protocol header */ if (get_protocol_http_header(version, &protocol_header)) string_list_append(&extra_headers, protocol_header.buf); memset(&http_options, 0, sizeof(http_options)); http_options.content_type = &type; http_options.charset = &charset; http_options.effective_url = &effective_url; http_options.base_url = &url; http_options.extra_headers = &extra_headers; http_options.initial_request = 1; http_options.no_cache = 1; http_options.keep_error = 1; http_ret = http_get_strbuf(refs_url.buf, &buffer, &http_options); switch (http_ret) { case HTTP_OK: break; case HTTP_MISSING_TARGET: show_http_message(&type, &charset, &buffer); die("repository '%s' not found", url.buf); case HTTP_NOAUTH: show_http_message(&type, &charset, &buffer); die("Authentication failed for '%s'", url.buf); default: show_http_message(&type, &charset, &buffer); die("unable to access '%s': %s", url.buf, curl_errorstr); } if (options.verbosity && !starts_with(refs_url.buf, url.buf)) warning(_("redirecting to %s"), url.buf); last= xcalloc(1, sizeof(*last_discovery)); last->service = xstrdup(service); last->buf_alloc = strbuf_detach(&buffer, &last->len); last->buf = last->buf_alloc; strbuf_addf(&exp, "application/x-%s-advertisement", service); if (maybe_smart && (5 <= last->len && last->buf[4] == '#') && !strbuf_cmp(&exp, &type)) { char *line; /* * smart HTTP response; validate that the service * pkt-line matches our request. */ line = packet_read_line_buf(&last->buf, &last->len, NULL); if (!line) die("invalid server response; expected service, got flush packet"); strbuf_reset(&exp); strbuf_addf(&exp, "# service=%s", service); if (strcmp(line, exp.buf)) die("invalid server response; got '%s'", line); strbuf_release(&exp); /* The header can include additional metadata lines, up * until a packet flush marker. Ignore these now, but * in the future we might start to scan them. */ while (packet_read_line_buf(&last->buf, &last->len, NULL)) ; last->proto_git = 1; } else if (maybe_smart && last->len > 5 && starts_with(last->buf + 4, "version 2")) { last->proto_git = 1; } if (last->proto_git) last->refs = parse_git_refs(last, for_push); else last->refs = parse_info_refs(last); strbuf_release(&refs_url); strbuf_release(&exp); strbuf_release(&type); strbuf_release(&charset); strbuf_release(&effective_url); strbuf_release(&buffer); strbuf_release(&protocol_header); string_list_clear(&extra_headers, 0); last_discovery = last; return last; }
int pager_in_use(void) { return git_env_bool("GIT_PAGER_IN_USE", 0); }
/* * Take an element of a pathspec and check for magic signatures. * Append the result to the prefix. Return the magic bitmap. * * For now, we only parse the syntax and throw out anything other than * "top" magic. * * NEEDSWORK: This needs to be rewritten when we start migrating * get_pathspec() users to use the "struct pathspec" interface. For * example, a pathspec element may be marked as case-insensitive, but * the prefix part must always match literally, and a single stupid * string cannot express such a case. */ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned *p_short_magic, const char **raw, unsigned flags, const char *prefix, int prefixlen, const char *elt) { static int literal_global = -1; static int glob_global = -1; static int noglob_global = -1; static int icase_global = -1; unsigned magic = 0, short_magic = 0, global_magic = 0; const char *copyfrom = elt, *long_magic_end = NULL; char *match; int i, pathspec_prefix = -1; if (literal_global < 0) literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0); if (literal_global) global_magic |= PATHSPEC_LITERAL; if (glob_global < 0) glob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0); if (glob_global) global_magic |= PATHSPEC_GLOB; if (noglob_global < 0) noglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0); if (glob_global && noglob_global) die(_("global 'glob' and 'noglob' pathspec settings are incompatible")); if (icase_global < 0) icase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0); if (icase_global) global_magic |= PATHSPEC_ICASE; if ((global_magic & PATHSPEC_LITERAL) && (global_magic & ~PATHSPEC_LITERAL)) die(_("global 'literal' pathspec setting is incompatible " "with all other global pathspec settings")); if (flags & PATHSPEC_LITERAL_PATH) global_magic = 0; if (elt[0] != ':' || literal_global || (flags & PATHSPEC_LITERAL_PATH)) { ; /* nothing to do */ } else if (elt[1] == '(') { /* longhand */ const char *nextat; for (copyfrom = elt + 2; *copyfrom && *copyfrom != ')'; copyfrom = nextat) { size_t len = strcspn(copyfrom, ",)"); if (copyfrom[len] == ',') nextat = copyfrom + len + 1; else /* handle ')' and '\0' */ nextat = copyfrom + len; if (!len) continue; for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) { if (strlen(pathspec_magic[i].name) == len && !strncmp(pathspec_magic[i].name, copyfrom, len)) { magic |= pathspec_magic[i].bit; break; } if (starts_with(copyfrom, "prefix:")) { char *endptr; pathspec_prefix = strtol(copyfrom + 7, &endptr, 10); if (endptr - copyfrom != len) die(_("invalid parameter for pathspec magic 'prefix'")); /* "i" would be wrong, but it does not matter */ break; } } if (ARRAY_SIZE(pathspec_magic) <= i) die(_("Invalid pathspec magic '%.*s' in '%s'"), (int) len, copyfrom, elt); } if (*copyfrom != ')') die(_("Missing ')' at the end of pathspec magic in '%s'"), elt); long_magic_end = copyfrom; copyfrom++; } else { /* shorthand */ for (copyfrom = elt + 1; *copyfrom && *copyfrom != ':'; copyfrom++) { char ch = *copyfrom; if (!is_pathspec_magic(ch)) break; for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) if (pathspec_magic[i].mnemonic == ch) { short_magic |= pathspec_magic[i].bit; break; } if (ARRAY_SIZE(pathspec_magic) <= i) die(_("Unimplemented pathspec magic '%c' in '%s'"), ch, elt); } if (*copyfrom == ':') copyfrom++; } magic |= short_magic; *p_short_magic = short_magic; /* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */ if (noglob_global && !(magic & PATHSPEC_GLOB)) global_magic |= PATHSPEC_LITERAL; /* --glob-pathspec is overridden by :(literal) */ if ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL)) global_magic &= ~PATHSPEC_GLOB; magic |= global_magic; if (pathspec_prefix >= 0 && (prefixlen || (prefix && *prefix))) die("BUG: 'prefix' magic is supposed to be used at worktree's root"); if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB)) die(_("%s: 'literal' and 'glob' are incompatible"), elt); if (pathspec_prefix >= 0) { match = xstrdup(copyfrom); prefixlen = pathspec_prefix; } else if (magic & PATHSPEC_FROMTOP) { match = xstrdup(copyfrom); prefixlen = 0; } else { match = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom); if (!match) die(_("%s: '%s' is outside repository"), elt, copyfrom); } *raw = item->match = match; /* * Prefix the pathspec (keep all magic) and assign to * original. Useful for passing to another command. */ if (flags & PATHSPEC_PREFIX_ORIGIN) { struct strbuf sb = STRBUF_INIT; const char *start = elt; if (prefixlen && !literal_global) { /* Preserve the actual prefix length of each pattern */ if (short_magic) die("BUG: prefixing on short magic is not supported"); else if (long_magic_end) { strbuf_add(&sb, start, long_magic_end - start); strbuf_addf(&sb, ",prefix:%d", prefixlen); start = long_magic_end; } else { if (*start == ':') start++; strbuf_addf(&sb, ":(prefix:%d)", prefixlen); } } strbuf_add(&sb, start, copyfrom - start); strbuf_addstr(&sb, match); item->original = strbuf_detach(&sb, NULL); } else item->original = elt; item->len = strlen(item->match); item->prefix = prefixlen; if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) && (item->len >= 1 && item->match[item->len - 1] == '/') && (i = cache_name_pos(item->match, item->len - 1)) >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) { item->len--; match[item->len] = '\0'; } if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE) for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; int ce_len = ce_namelen(ce); if (!S_ISGITLINK(ce->ce_mode)) continue; if (item->len <= ce_len || match[ce_len] != '/' || memcmp(ce->name, match, ce_len)) continue; if (item->len == ce_len + 1) { /* strip trailing slash */ item->len--; match[item->len] = '\0'; } else die (_("Pathspec '%s' is in submodule '%.*s'"), elt, ce_len, ce->name); } if (magic & PATHSPEC_LITERAL) item->nowildcard_len = item->len; else { item->nowildcard_len = simple_length(item->match); if (item->nowildcard_len < prefixlen) item->nowildcard_len = prefixlen; } item->flags = 0; if (magic & PATHSPEC_GLOB) { /* * FIXME: should we enable ONESTAR in _GLOB for * pattern "* * / * . c"? */ } else { if (item->nowildcard_len < item->len && item->match[item->nowildcard_len] == '*' && no_wildcard(item->match + item->nowildcard_len + 1)) item->flags |= PATHSPEC_ONESTAR; } /* sanity checks, pathspec matchers assume these are sane */ assert(item->nowildcard_len <= item->len && item->prefix <= item->len); return magic; }
static struct discovery* discover_refs(const char *service) { struct strbuf buffer = STRBUF_INIT; struct discovery *last = last_discovery; char *refs_url; int http_ret, maybe_smart = 0; if (last && !strcmp(service, last->service)) return last; free_discovery(last); strbuf_addf(&buffer, "%sinfo/refs", url); if ((!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) && git_env_bool("GIT_SMART_HTTP", 1)) { maybe_smart = 1; if (!strchr(url, '?')) strbuf_addch(&buffer, '?'); else strbuf_addch(&buffer, '&'); strbuf_addf(&buffer, "service=%s", service); } refs_url = strbuf_detach(&buffer, NULL); http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE); switch (http_ret) { case HTTP_OK: break; case HTTP_MISSING_TARGET: die("%s not found: did you run git update-server-info on the" " server?", refs_url); case HTTP_NOAUTH: die("Authentication failed"); default: http_error(refs_url, http_ret); die("HTTP request failed"); } last= xcalloc(1, sizeof(*last_discovery)); last->service = service; last->buf_alloc = strbuf_detach(&buffer, &last->len); last->buf = last->buf_alloc; if (maybe_smart && 5 <= last->len && last->buf[4] == '#') { /* smart HTTP response; validate that the service * pkt-line matches our request. */ struct strbuf exp = STRBUF_INIT; if (packet_get_line(&buffer, &last->buf, &last->len) <= 0) die("%s has invalid packet header", refs_url); if (buffer.len && buffer.buf[buffer.len - 1] == '\n') strbuf_setlen(&buffer, buffer.len - 1); strbuf_addf(&exp, "# service=%s", service); if (strbuf_cmp(&exp, &buffer)) die("invalid server response; got '%s'", buffer.buf); strbuf_release(&exp); /* The header can include additional metadata lines, up * until a packet flush marker. Ignore these now, but * in the future we might start to scan them. */ strbuf_reset(&buffer); while (packet_get_line(&buffer, &last->buf, &last->len) > 0) strbuf_reset(&buffer); last->proto_git = 1; } free(refs_url); strbuf_release(&buffer); last_discovery = last; return last; }
int git_config_global(void) { return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0); }
/* * We cannot decide in this function whether we are in the work tree or * not, since the config can only be read _after_ this function was called. */ static const char *setup_git_directory_gently_1(int *nongit_ok) { const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT); static char cwd[PATH_MAX+1]; const char *gitdirenv, *ret; char *gitfile; int len, offset, ceil_offset; dev_t current_device = 0; int one_filesystem = 1; /* * Let's assume that we are in a git repository. * If it turns out later that we are somewhere else, the value will be * updated accordingly. */ if (nongit_ok) *nongit_ok = 0; if (!getcwd(cwd, sizeof(cwd)-1)) die_errno("Unable to read current working directory"); offset = len = strlen(cwd); /* * If GIT_DIR is set explicitly, we're not going * to do any discovery, but we still do repository * validation. */ gitdirenv = getenv(GIT_DIR_ENVIRONMENT); if (gitdirenv) return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok); ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs); if (ceil_offset < 0 && has_dos_drive_prefix(cwd)) ceil_offset = 1; /* * Test in the following order (relative to the cwd): * - .git (file containing "gitdir: <path>") * - .git/ * - ./ (bare) * - ../.git * - ../.git/ * - ../ (bare) * - ../../.git/ * etc. */ one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0); if (one_filesystem) current_device = get_device_or_die(".", NULL); for (;;) { gitfile = (char*)read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT); if (gitfile) gitdirenv = gitfile = xstrdup(gitfile); else { if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT)) gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT; } if (gitdirenv) { ret = setup_discovered_git_dir(gitdirenv, cwd, offset, len, nongit_ok); free(gitfile); return ret; } free(gitfile); if (is_git_directory(".")) return setup_bare_git_dir(cwd, offset, len, nongit_ok); while (--offset > ceil_offset && cwd[offset] != '/'); if (offset <= ceil_offset) return setup_nongit(cwd, nongit_ok); if (one_filesystem) { dev_t parent_device = get_device_or_die("..", cwd); if (parent_device != current_device) { if (nongit_ok) { if (chdir(cwd)) die_errno("Cannot come back to cwd"); *nongit_ok = 1; return NULL; } cwd[offset] = '\0'; die("Not a git repository (or any parent up to mount parent %s)\n" "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", cwd); } } if (chdir("..")) { cwd[offset] = '\0'; die_errno("Cannot change to '%s/..'", cwd); } } }
static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, int fd[2], const struct ref *orig_ref, struct ref **sought, int nr_sought, char **pack_lockfile) { struct ref *ref = copy_ref_list(orig_ref); enum fetch_state state = FETCH_CHECK_LOCAL; struct oidset common = OIDSET_INIT; struct packet_reader reader; int in_vain = 0; int haves_to_send = INITIAL_FLUSH; struct fetch_negotiator negotiator; fetch_negotiator_init(&negotiator, negotiation_algorithm); packet_reader_init(&reader, fd[0], NULL, 0, PACKET_READ_CHOMP_NEWLINE | PACKET_READ_DIE_ON_ERR_PACKET); if (git_env_bool("GIT_TEST_SIDEBAND_ALL", 1) && server_supports_feature("fetch", "sideband-all", 0)) { reader.use_sideband = 1; reader.me = "fetch-pack"; } while (state != FETCH_DONE) { switch (state) { case FETCH_CHECK_LOCAL: sort_ref_list(&ref, ref_compare_name); QSORT(sought, nr_sought, cmp_ref_by_name); /* v2 supports these by default */ allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1; use_sideband = 2; if (args->depth > 0 || args->deepen_since || args->deepen_not) args->deepen = 1; /* Filter 'ref' by 'sought' and those that aren't local */ if (!args->no_dependents) { mark_complete_and_common_ref(&negotiator, args, &ref); filter_refs(args, &ref, sought, nr_sought); if (everything_local(args, &ref)) state = FETCH_DONE; else state = FETCH_SEND_REQUEST; mark_tips(&negotiator, args->negotiation_tips); for_each_cached_alternate(&negotiator, insert_one_alternate_object); } else { filter_refs(args, &ref, sought, nr_sought); state = FETCH_SEND_REQUEST; } break; case FETCH_SEND_REQUEST: if (send_fetch_request(&negotiator, fd[1], args, ref, &common, &haves_to_send, &in_vain, reader.use_sideband)) state = FETCH_GET_PACK; else state = FETCH_PROCESS_ACKS; break; case FETCH_PROCESS_ACKS: /* Process ACKs/NAKs */ switch (process_acks(&negotiator, &reader, &common)) { case 2: state = FETCH_GET_PACK; break; case 1: in_vain = 0; /* fallthrough */ default: state = FETCH_SEND_REQUEST; break; } break; case FETCH_GET_PACK: /* Check for shallow-info section */ if (process_section_header(&reader, "shallow-info", 1)) receive_shallow_info(args, &reader); if (process_section_header(&reader, "wanted-refs", 1)) receive_wanted_refs(&reader, sought, nr_sought); /* get the pack */ process_section_header(&reader, "packfile", 0); if (get_pack(args, fd, pack_lockfile)) die(_("git fetch-pack: fetch failed.")); state = FETCH_DONE; break; case FETCH_DONE: continue; } } negotiator.release(&negotiator); oidset_clear(&common); return ref; }