diff options
Diffstat (limited to 'builtin/init-db.c')
-rw-r--r-- | builtin/init-db.c | 212 |
1 files changed, 112 insertions, 100 deletions
diff --git a/builtin/init-db.c b/builtin/init-db.c index 6223b7d46a..12ddda7e7b 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -4,9 +4,10 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "config.h" #include "refs.h" #include "builtin.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "parse-options.h" #ifndef DEFAULT_GIT_TEMPLATE_DIR @@ -22,13 +23,12 @@ static int init_is_bare_repository = 0; static int init_shared_repository = -1; static const char *init_db_template_dir; -static const char *git_link; -static void copy_templates_1(struct strbuf *path, struct strbuf *template, +static void copy_templates_1(struct strbuf *path, struct strbuf *template_path, DIR *dir) { size_t path_baselen = path->len; - size_t template_baselen = template->len; + size_t template_baselen = template_path->len; struct dirent *de; /* Note: if ".git/hooks" file exists in the repository being @@ -44,12 +44,12 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template, int exists = 0; strbuf_setlen(path, path_baselen); - strbuf_setlen(template, template_baselen); + strbuf_setlen(template_path, template_baselen); if (de->d_name[0] == '.') continue; strbuf_addstr(path, de->d_name); - strbuf_addstr(template, de->d_name); + strbuf_addstr(template_path, de->d_name); if (lstat(path->buf, &st_git)) { if (errno != ENOENT) die_errno(_("cannot stat '%s'"), path->buf); @@ -57,36 +57,37 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template, else exists = 1; - if (lstat(template->buf, &st_template)) - die_errno(_("cannot stat template '%s'"), template->buf); + if (lstat(template_path->buf, &st_template)) + die_errno(_("cannot stat template '%s'"), template_path->buf); if (S_ISDIR(st_template.st_mode)) { - DIR *subdir = opendir(template->buf); + DIR *subdir = opendir(template_path->buf); if (!subdir) - die_errno(_("cannot opendir '%s'"), template->buf); + die_errno(_("cannot opendir '%s'"), template_path->buf); strbuf_addch(path, '/'); - strbuf_addch(template, '/'); - copy_templates_1(path, template, subdir); + strbuf_addch(template_path, '/'); + copy_templates_1(path, template_path, subdir); closedir(subdir); } else if (exists) continue; else if (S_ISLNK(st_template.st_mode)) { struct strbuf lnk = STRBUF_INIT; - if (strbuf_readlink(&lnk, template->buf, 0) < 0) - die_errno(_("cannot readlink '%s'"), template->buf); + if (strbuf_readlink(&lnk, template_path->buf, + st_template.st_size) < 0) + die_errno(_("cannot readlink '%s'"), template_path->buf); if (symlink(lnk.buf, path->buf)) die_errno(_("cannot symlink '%s' '%s'"), lnk.buf, path->buf); strbuf_release(&lnk); } else if (S_ISREG(st_template.st_mode)) { - if (copy_file(path->buf, template->buf, st_template.st_mode)) + if (copy_file(path->buf, template_path->buf, st_template.st_mode)) die_errno(_("cannot copy '%s' to '%s'"), - template->buf, path->buf); + template_path->buf, path->buf); } else - error(_("ignoring template %s"), template->buf); + error(_("ignoring template %s"), template_path->buf); } } @@ -95,6 +96,8 @@ static void copy_templates(const char *template_dir) struct strbuf path = STRBUF_INIT; struct strbuf template_path = STRBUF_INIT; size_t template_len; + struct repository_format template_format; + struct strbuf err = STRBUF_INIT; DIR *dir; char *to_free = NULL; @@ -115,27 +118,28 @@ static void copy_templates(const char *template_dir) dir = opendir(template_path.buf); if (!dir) { - warning(_("templates not found %s"), template_dir); + warning(_("templates not found in %s"), template_dir); goto free_return; } /* Make sure that template is from the correct vintage */ strbuf_addstr(&template_path, "config"); - repository_format_version = 0; - git_config_from_file(check_repository_format_version, - template_path.buf, NULL); + read_repository_format(&template_format, template_path.buf); strbuf_setlen(&template_path, template_len); - if (repository_format_version && - repository_format_version != GIT_REPO_VERSION) { - warning(_("not copying templates of " - "a wrong format version %d from '%s'"), - repository_format_version, - template_dir); + /* + * No mention of version at all is OK, but anything else should be + * verified. + */ + if (template_format.version >= 0 && + verify_repository_format(&template_format, &err) < 0) { + warning(_("not copying templates from '%s': %s"), + template_dir, err.buf); + strbuf_release(&err); goto close_free_return; } - strbuf_addstr(&path, get_git_dir()); + strbuf_addstr(&path, get_git_common_dir()); strbuf_complete(&path, '/'); copy_templates_1(&path, &template_path, dir); close_free_return: @@ -168,7 +172,8 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree) return 1; } -static int create_default_files(const char *template_path) +static int create_default_files(const char *template_path, + const char *original_git_dir) { struct stat st1; struct strbuf buf = STRBUF_INIT; @@ -177,42 +182,52 @@ static int create_default_files(const char *template_path) char junk[2]; int reinit; int filemode; - - /* - * Create .git/refs/{heads,tags} - */ - safe_create_dir(git_path_buf(&buf, "refs"), 1); - safe_create_dir(git_path_buf(&buf, "refs/heads"), 1); - safe_create_dir(git_path_buf(&buf, "refs/tags"), 1); + struct strbuf err = STRBUF_INIT; /* Just look for `init.templatedir` */ git_config(git_init_db_config, NULL); - /* First copy the templates -- we might have the default + /* + * First copy the templates -- we might have the default * config file there, in which case we would want to read * from it after installing. + * + * Before reading that config, we also need to clear out any cached + * values (since we've just potentially changed what's available on + * disk). */ copy_templates(template_path); - + git_config_clear(); + reset_shared_repository(); git_config(git_default_config, NULL); - is_bare_repository_cfg = init_is_bare_repository; - /* reading existing config may have overwrote it */ + /* + * We must make sure command-line options continue to override any + * values we might have just re-read from the config. + */ + is_bare_repository_cfg = init_is_bare_repository; if (init_shared_repository != -1) - shared_repository = init_shared_repository; + set_shared_repository(init_shared_repository); /* * We would have created the above under user's umask -- under * shared-repository settings, we would need to fix them up. */ - if (shared_repository) { + if (get_shared_repository()) { adjust_shared_perm(get_git_dir()); - adjust_shared_perm(git_path_buf(&buf, "refs")); - adjust_shared_perm(git_path_buf(&buf, "refs/heads")); - adjust_shared_perm(git_path_buf(&buf, "refs/tags")); } /* + * We need to create a "refs" dir in any case so that older + * versions of git can tell that this is a repository. + */ + safe_create_dir(git_path("refs"), 1); + adjust_shared_perm(git_path("refs")); + + if (refs_init_db(&err)) + die("failed to set up refs db: %s", err.buf); + + /* * Create the default symlink from ".git/HEAD" to the "master" * branch, if it does not exist yet. */ @@ -249,9 +264,9 @@ static int create_default_files(const char *template_path) const char *work_tree = get_git_work_tree(); git_config_set("core.bare", "false"); /* allow template config file to override the default */ - if (log_all_ref_updates == -1) + if (log_all_ref_updates == LOG_REFS_UNSET) git_config_set("core.logallrefupdates", "true"); - if (needs_work_tree_config(get_git_dir(), work_tree)) + if (needs_work_tree_config(original_git_dir, work_tree)) git_config_set("core.worktree", work_tree); } @@ -299,33 +314,7 @@ static void create_object_directory(void) strbuf_release(&path); } -int set_git_dir_init(const char *git_dir, const char *real_git_dir, - int exist_ok) -{ - if (real_git_dir) { - struct stat st; - - if (!exist_ok && !stat(git_dir, &st)) - die(_("%s already exists"), git_dir); - - if (!exist_ok && !stat(real_git_dir, &st)) - die(_("%s already exists"), real_git_dir); - - /* - * make sure symlinks are resolved because we'll be - * moving the target repo later on in separate_git_dir() - */ - git_link = xstrdup(real_path(git_dir)); - set_git_dir(real_path(real_git_dir)); - } - else { - set_git_dir(real_path(git_dir)); - git_link = NULL; - } - return 0; -} - -static void separate_git_dir(const char *git_dir) +static void separate_git_dir(const char *git_dir, const char *git_link) { struct stat st; @@ -346,13 +335,31 @@ static void separate_git_dir(const char *git_dir) write_file(git_link, "gitdir: %s", git_dir); } -int init_db(const char *template_dir, unsigned int flags) +int init_db(const char *git_dir, const char *real_git_dir, + const char *template_dir, unsigned int flags) { int reinit; - const char *git_dir = get_git_dir(); + int exist_ok = flags & INIT_DB_EXIST_OK; + char *original_git_dir = real_pathdup(git_dir, 1); + + if (real_git_dir) { + struct stat st; - if (git_link) - separate_git_dir(git_dir); + if (!exist_ok && !stat(git_dir, &st)) + die(_("%s already exists"), git_dir); + + if (!exist_ok && !stat(real_git_dir, &st)) + die(_("%s already exists"), real_git_dir); + + set_git_dir(real_path(real_git_dir)); + git_dir = get_git_dir(); + separate_git_dir(git_dir, original_git_dir); + } + else { + set_git_dir(real_path(git_dir)); + git_dir = get_git_dir(); + } + startup_info->have_repository = 1; safe_create_dir(git_dir, 0); @@ -365,11 +372,11 @@ int init_db(const char *template_dir, unsigned int flags) */ check_repository_format(); - reinit = create_default_files(template_dir); + reinit = create_default_files(template_dir, original_git_dir); create_object_directory(); - if (shared_repository) { + if (get_shared_repository()) { char buf[10]; /* We do not spell "group" and such, so that * the configuration can be read by older version @@ -377,15 +384,15 @@ int init_db(const char *template_dir, unsigned int flags) * and compatibility values for PERM_GROUP and * PERM_EVERYBODY. */ - if (shared_repository < 0) + if (get_shared_repository() < 0) /* force to the mode value */ - xsnprintf(buf, sizeof(buf), "0%o", -shared_repository); - else if (shared_repository == PERM_GROUP) + xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository()); + else if (get_shared_repository() == PERM_GROUP) xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP); - else if (shared_repository == PERM_EVERYBODY) + else if (get_shared_repository() == PERM_EVERYBODY) xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY); else - die("BUG: invalid value for shared_repository"); + BUG("invalid value for shared_repository"); git_config_set("core.sharedrepository", buf); git_config_set("receive.denyNonFastforwards", "true"); } @@ -393,15 +400,19 @@ int init_db(const char *template_dir, unsigned int flags) if (!(flags & INIT_DB_QUIET)) { int len = strlen(git_dir); - /* TRANSLATORS: The first '%s' is either "Reinitialized - existing" or "Initialized empty", the second " shared" or - "", and the last '%s%s' is the verbatim directory name. */ - printf(_("%s%s Git repository in %s%s\n"), - reinit ? _("Reinitialized existing") : _("Initialized empty"), - shared_repository ? _(" shared") : "", - git_dir, len && git_dir[len-1] != '/' ? "/" : ""); + if (reinit) + printf(get_shared_repository() + ? _("Reinitialized existing shared Git repository in %s%s\n") + : _("Reinitialized existing Git repository in %s%s\n"), + git_dir, len && git_dir[len-1] != '/' ? "/" : ""); + else + printf(get_shared_repository() + ? _("Initialized empty shared Git repository in %s%s\n") + : _("Initialized empty Git repository in %s%s\n"), + git_dir, len && git_dir[len-1] != '/' ? "/" : ""); } + free(original_git_dir); return 0; } @@ -480,7 +491,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0); if (real_git_dir && !is_absolute_path(real_git_dir)) - real_git_dir = xstrdup(real_path(real_git_dir)); + real_git_dir = real_pathdup(real_git_dir, 1); if (argc == 1) { int mkdir_tried = 0; @@ -493,8 +504,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) * and we know shared_repository should always be 0; * but just in case we play safe. */ - saved = shared_repository; - shared_repository = 0; + saved = get_shared_repository(); + set_shared_repository(0); switch (safe_create_leading_directories_const(argv[0])) { case SCLD_OK: case SCLD_PERMS: @@ -506,7 +517,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) die_errno(_("cannot mkdir %s"), argv[0]); break; } - shared_repository = saved; + set_shared_repository(saved); if (mkdir(argv[0], 0777) < 0) die_errno(_("cannot mkdir %s"), argv[0]); mkdir_tried = 1; @@ -524,7 +535,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) } if (init_shared_repository != -1) - shared_repository = init_shared_repository; + set_shared_repository(init_shared_repository); /* * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR @@ -551,7 +562,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) const char *git_dir_parent = strrchr(git_dir, '/'); if (git_dir_parent) { char *rel = xstrndup(git_dir, git_dir_parent - git_dir); - git_work_tree_cfg = xstrdup(real_path(rel)); + git_work_tree_cfg = real_pathdup(rel, 1); free(rel); } if (!git_work_tree_cfg) @@ -569,7 +580,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) set_git_work_tree(work_tree); } - set_git_dir_init(git_dir, real_git_dir, 1); + UNLEAK(real_git_dir); - return init_db(template_dir, flags); + flags |= INIT_DB_EXIST_OK; + return init_db(git_dir, real_git_dir, template_dir, flags); } |