diff options
Diffstat (limited to 'setup.c')
| -rw-r--r-- | setup.c | 189 |
1 files changed, 155 insertions, 34 deletions
@@ -4,6 +4,7 @@ #include "environment.h" #include "exec-cmd.h" #include "gettext.h" +#include "hex.h" #include "object-name.h" #include "refs.h" #include "repository.h" @@ -16,6 +17,7 @@ #include "quote.h" #include "trace2.h" #include "worktree.h" +#include "exec-cmd.h" static int inside_git_dir = -1; static int inside_work_tree = -1; @@ -341,6 +343,58 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir) return ret; } +static int validate_headref(const char *path) +{ + struct stat st; + char buffer[256]; + const char *refname; + struct object_id oid; + int fd; + ssize_t len; + + if (lstat(path, &st) < 0) + return -1; + + /* Make sure it is a "refs/.." symlink */ + if (S_ISLNK(st.st_mode)) { + len = readlink(path, buffer, sizeof(buffer)-1); + if (len >= 5 && !memcmp("refs/", buffer, 5)) + return 0; + return -1; + } + + /* + * Anything else, just open it and try to see if it is a symbolic ref. + */ + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + len = read_in_full(fd, buffer, sizeof(buffer)-1); + close(fd); + + if (len < 0) + return -1; + buffer[len] = '\0'; + + /* + * Is it a symbolic ref? + */ + if (skip_prefix(buffer, "ref:", &refname)) { + while (isspace(*refname)) + refname++; + if (starts_with(refname, "refs/")) + return 0; + } + + /* + * Is this a detached HEAD? + */ + if (get_oid_hex_any(buffer, &oid) != GIT_HASH_UNKNOWN) + return 0; + + return -1; +} + /* * Test if it looks like we're at a git directory. * We want to see: @@ -1176,21 +1230,20 @@ static int safe_directory_cb(const char *key, const char *value, } else if (!strcmp(value, "*")) { data->is_safe = 1; } else { - const char *allowed = NULL; + char *allowed = NULL; if (!git_config_pathname(&allowed, key, value)) { - if (!allowed) - allowed = value; - if (ends_with(allowed, "/*")) { - size_t len = strlen(allowed); - if (!fspathncmp(allowed, data->path, len - 1)) + const char *check = allowed ? allowed : value; + if (ends_with(check, "/*")) { + size_t len = strlen(check); + if (!fspathncmp(check, data->path, len - 1)) data->is_safe = 1; - } else if (!fspathcmp(data->path, allowed)) { + } else if (!fspathcmp(data->path, check)) { data->is_safe = 1; } } if (allowed != value) - free((char *)allowed); + free(allowed); } return 0; @@ -1228,6 +1281,27 @@ static int ensure_valid_ownership(const char *gitfile, return data.is_safe; } +void die_upon_dubious_ownership(const char *gitfile, const char *worktree, + const char *gitdir) +{ + struct strbuf report = STRBUF_INIT, quoted = STRBUF_INIT; + const char *path; + + if (ensure_valid_ownership(gitfile, worktree, gitdir, &report)) + return; + + strbuf_complete(&report, '\n'); + path = gitfile ? gitfile : gitdir; + sq_quote_buf_pretty("ed, path); + + die(_("detected dubious ownership in repository at '%s'\n" + "%s" + "To add an exception for this directory, call:\n" + "\n" + "\tgit config --global --add safe.directory %s"), + path, report.buf, quoted.buf); +} + static int allowed_bare_repo_cb(const char *key, const char *value, const struct config_context *ctx UNUSED, void *d) @@ -1789,6 +1863,57 @@ int daemonize(void) #endif } +struct template_dir_cb_data { + char *path; + int initialized; +}; + +static int template_dir_cb(const char *key, const char *value, + const struct config_context *ctx, void *d) +{ + struct template_dir_cb_data *data = d; + + if (strcmp(key, "init.templatedir")) + return 0; + + if (!value) { + data->path = NULL; + } else { + char *path = NULL; + + FREE_AND_NULL(data->path); + if (!git_config_pathname(&path, key, value)) + data->path = path ? path : xstrdup(value); + } + + return 0; +} + +const char *get_template_dir(const char *option_template) +{ + const char *template_dir = option_template; + + if (!template_dir) + template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT); + if (!template_dir) { + static struct template_dir_cb_data data; + + if (!data.initialized) { + git_protected_config(template_dir_cb, &data); + data.initialized = 1; + } + template_dir = data.path; + } + if (!template_dir) { + static char *dir; + + if (!dir) + dir = system_path(DEFAULT_GIT_TEMPLATE_DIR); + template_dir = dir; + } + return template_dir; +} + #ifdef NO_TRUSTABLE_FILEMODE #define TEST_FILEMODE 0 #else @@ -1864,8 +1989,9 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template_path, } } -static void copy_templates(const char *template_dir, const char *init_template_dir) +static void copy_templates(const char *option_template) { + const char *template_dir = get_template_dir(option_template); struct strbuf path = STRBUF_INIT; struct strbuf template_path = STRBUF_INIT; size_t template_len; @@ -1874,16 +2000,8 @@ static void copy_templates(const char *template_dir, const char *init_template_d DIR *dir; char *to_free = NULL; - if (!template_dir) - template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT); - if (!template_dir) - template_dir = init_template_dir; - if (!template_dir) - template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR); - if (!template_dir[0]) { - free(to_free); + if (!template_dir || !*template_dir) return; - } strbuf_addstr(&template_path, template_dir); strbuf_complete(&template_path, '/'); @@ -1988,10 +2106,11 @@ void create_reference_database(unsigned int ref_storage_format, const char *initial_branch, int quiet) { struct strbuf err = STRBUF_INIT; + char *to_free = NULL; int reinit = is_reinit(); repo_set_ref_storage_format(the_repository, ref_storage_format); - if (refs_init_db(get_main_ref_store(the_repository), 0, &err)) + if (ref_store_create_on_disk(get_main_ref_store(the_repository), 0, &err)) die("failed to set up refs db: %s", err.buf); /* @@ -2002,14 +2121,15 @@ void create_reference_database(unsigned int ref_storage_format, char *ref; if (!initial_branch) - initial_branch = git_default_branch_name(quiet); + initial_branch = to_free = + repo_default_branch_name(the_repository, quiet); ref = xstrfmt("refs/heads/%s", initial_branch); if (check_refname_format(ref, 0) < 0) die(_("invalid initial branch name: '%s'"), initial_branch); - if (create_symref("HEAD", ref, NULL) < 0) + if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", ref, NULL) < 0) exit(1); free(ref); } @@ -2019,6 +2139,7 @@ void create_reference_database(unsigned int ref_storage_format, initial_branch); strbuf_release(&err); + free(to_free); } static int create_default_files(const char *template_path, @@ -2031,7 +2152,6 @@ static int create_default_files(const char *template_path, char *path; int reinit; int filemode; - const char *init_template_dir = NULL; const char *work_tree = get_git_work_tree(); /* @@ -2043,9 +2163,7 @@ static int create_default_files(const char *template_path, * values (since we've just potentially changed what's available on * disk). */ - git_config_get_pathname("init.templatedir", &init_template_dir); - copy_templates(template_path, init_template_dir); - free((char *)init_template_dir); + copy_templates(template_path); git_config_clear(); reset_shared_repository(); git_config(git_default_config, NULL); @@ -2231,12 +2349,6 @@ int init_db(const char *git_dir, const char *real_git_dir, } startup_info->have_repository = 1; - /* Ensure `core.hidedotfiles` is processed */ - git_config(platform_core_config, NULL); - - safe_create_dir(git_dir, 0); - - /* Check to see if the repository version is right. * Note that a newly created repository does not have * config file, so this will not fail. What we are catching @@ -2247,9 +2359,6 @@ int init_db(const char *git_dir, const char *real_git_dir, validate_hash_algorithm(&repo_fmt, hash); validate_ref_storage_format(&repo_fmt, ref_storage_format); - reinit = create_default_files(template_dir, original_git_dir, - &repo_fmt, init_shared_repository); - /* * Now that we have set up both the hash algorithm and the ref storage * format we can update the repository's settings accordingly. @@ -2257,6 +2366,18 @@ int init_db(const char *git_dir, const char *real_git_dir, repo_set_hash_algo(the_repository, repo_fmt.hash_algo); repo_set_ref_storage_format(the_repository, repo_fmt.ref_storage_format); + /* + * Ensure `core.hidedotfiles` is processed. This must happen after we + * have set up the repository format such that we can evaluate + * includeIf conditions correctly in the case of re-initialization. + */ + git_config(platform_core_config, NULL); + + safe_create_dir(git_dir, 0); + + reinit = create_default_files(template_dir, original_git_dir, + &repo_fmt, init_shared_repository); + if (!(flags & INIT_DB_SKIP_REFDB)) create_reference_database(repo_fmt.ref_storage_format, initial_branch, flags & INIT_DB_QUIET); |
