diff options
Diffstat (limited to 'builtin/init-db.c')
-rw-r--r-- | builtin/init-db.c | 251 |
1 files changed, 108 insertions, 143 deletions
diff --git a/builtin/init-db.c b/builtin/init-db.c index ab9f86b889..b2d8d40a67 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -4,6 +4,7 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "refs.h" #include "builtin.h" #include "exec_cmd.h" #include "parse-options.h" @@ -23,22 +24,11 @@ static int init_shared_repository = -1; static const char *init_db_template_dir; static const char *git_link; -static void safe_create_dir(const char *dir, int share) -{ - if (mkdir(dir, 0777) < 0) { - if (errno != EEXIST) { - perror(dir); - exit(1); - } - } - else if (share && adjust_shared_perm(dir)) - die(_("Could not make %s writable by group"), dir); -} - -static void copy_templates_1(char *path, int baselen, - char *template, int template_baselen, +static void copy_templates_1(struct strbuf *path, struct strbuf *template, DIR *dir) { + size_t path_baselen = path->len; + size_t template_baselen = template->len; struct dirent *de; /* Note: if ".git/hooks" file exists in the repository being @@ -48,77 +38,66 @@ static void copy_templates_1(char *path, int baselen, * with the way the namespace under .git/ is organized, should * be really carefully chosen. */ - safe_create_dir(path, 1); + safe_create_dir(path->buf, 1); while ((de = readdir(dir)) != NULL) { struct stat st_git, st_template; - int namelen; int exists = 0; + strbuf_setlen(path, path_baselen); + strbuf_setlen(template, template_baselen); + if (de->d_name[0] == '.') continue; - namelen = strlen(de->d_name); - if ((PATH_MAX <= baselen + namelen) || - (PATH_MAX <= template_baselen + namelen)) - die(_("insanely long template name %s"), de->d_name); - memcpy(path + baselen, de->d_name, namelen+1); - memcpy(template + template_baselen, de->d_name, namelen+1); - if (lstat(path, &st_git)) { + strbuf_addstr(path, de->d_name); + strbuf_addstr(template, de->d_name); + if (lstat(path->buf, &st_git)) { if (errno != ENOENT) - die_errno(_("cannot stat '%s'"), path); + die_errno(_("cannot stat '%s'"), path->buf); } else exists = 1; - if (lstat(template, &st_template)) - die_errno(_("cannot stat template '%s'"), template); + if (lstat(template->buf, &st_template)) + die_errno(_("cannot stat template '%s'"), template->buf); if (S_ISDIR(st_template.st_mode)) { - DIR *subdir = opendir(template); - int baselen_sub = baselen + namelen; - int template_baselen_sub = template_baselen + namelen; + DIR *subdir = opendir(template->buf); if (!subdir) - die_errno(_("cannot opendir '%s'"), template); - path[baselen_sub++] = - template[template_baselen_sub++] = '/'; - path[baselen_sub] = - template[template_baselen_sub] = 0; - copy_templates_1(path, baselen_sub, - template, template_baselen_sub, - subdir); + die_errno(_("cannot opendir '%s'"), template->buf); + strbuf_addch(path, '/'); + strbuf_addch(template, '/'); + copy_templates_1(path, template, subdir); closedir(subdir); } else if (exists) continue; else if (S_ISLNK(st_template.st_mode)) { - char lnk[256]; - int len; - len = readlink(template, lnk, sizeof(lnk)); - if (len < 0) - die_errno(_("cannot readlink '%s'"), template); - if (sizeof(lnk) <= len) - die(_("insanely long symlink %s"), template); - lnk[len] = 0; - if (symlink(lnk, path)) - die_errno(_("cannot symlink '%s' '%s'"), lnk, path); + struct strbuf lnk = STRBUF_INIT; + if (strbuf_readlink(&lnk, template->buf, 0) < 0) + die_errno(_("cannot readlink '%s'"), template->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, template, st_template.st_mode)) - die_errno(_("cannot copy '%s' to '%s'"), template, - path); + if (copy_file(path->buf, template->buf, st_template.st_mode)) + die_errno(_("cannot copy '%s' to '%s'"), + template->buf, path->buf); } else - error(_("ignoring template %s"), template); + error(_("ignoring template %s"), template->buf); } } static void copy_templates(const char *template_dir) { - char path[PATH_MAX]; - char template_path[PATH_MAX]; - int template_len; + 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; - const char *git_dir = get_git_dir(); - int len = strlen(git_dir); char *to_free = NULL; if (!template_dir) @@ -131,47 +110,43 @@ static void copy_templates(const char *template_dir) free(to_free); return; } - template_len = strlen(template_dir); - if (PATH_MAX <= (template_len+strlen("/config"))) - die(_("insanely long template path %s"), template_dir); - strcpy(template_path, template_dir); - if (template_path[template_len-1] != '/') { - template_path[template_len++] = '/'; - template_path[template_len] = 0; - } - dir = opendir(template_path); + + strbuf_addstr(&template_path, template_dir); + strbuf_complete(&template_path, '/'); + template_len = template_path.len; + + dir = opendir(template_path.buf); if (!dir) { warning(_("templates not found %s"), template_dir); goto free_return; } /* Make sure that template is from the correct vintage */ - strcpy(template_path + template_len, "config"); - repository_format_version = 0; - git_config_from_file(check_repository_format_version, - template_path, NULL); - template_path[template_len] = 0; - - 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); + strbuf_addstr(&template_path, "config"); + read_repository_format(&template_format, template_path.buf); + strbuf_setlen(&template_path, template_len); + + /* + * 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; } - memcpy(path, git_dir, len); - if (len && path[len - 1] != '/') - path[len++] = '/'; - path[len] = 0; - copy_templates_1(path, len, - template_path, template_len, - dir); + strbuf_addstr(&path, get_git_dir()); + strbuf_complete(&path, '/'); + copy_templates_1(&path, &template_path, dir); close_free_return: closedir(dir); free_return: free(to_free); + strbuf_release(&path); + strbuf_release(&template_path); } static int git_init_db_config(const char *k, const char *v, void *cb) @@ -198,28 +173,20 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree) static int create_default_files(const char *template_path) { - const char *git_dir = get_git_dir(); - unsigned len = strlen(git_dir); - static char path[PATH_MAX]; struct stat st1; + struct strbuf buf = STRBUF_INIT; + char *path; char repo_version_string[10]; char junk[2]; int reinit; int filemode; - if (len > sizeof(path)-50) - die(_("insane git directory %s"), git_dir); - memcpy(path, git_dir, len); - - if (len && path[len-1] != '/') - path[len++] = '/'; - /* * Create .git/refs/{heads,tags} */ - safe_create_dir(git_path("refs"), 1); - safe_create_dir(git_path("refs/heads"), 1); - safe_create_dir(git_path("refs/tags"), 1); + 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); /* Just look for `init.templatedir` */ git_config(git_init_db_config, NULL); @@ -235,24 +202,24 @@ static int create_default_files(const char *template_path) /* reading existing config may have overwrote it */ 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("refs")); - adjust_shared_perm(git_path("refs/heads")); - adjust_shared_perm(git_path("refs/tags")); + 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")); } /* * Create the default symlink from ".git/HEAD" to the "master" * branch, if it does not exist yet. */ - strcpy(path + len, "HEAD"); + path = git_path_buf(&buf, "HEAD"); reinit = (!access(path, R_OK) || readlink(path, junk, sizeof(junk)-1) != -1); if (!reinit) { @@ -261,13 +228,12 @@ static int create_default_files(const char *template_path) } /* This forces creation of new config file */ - sprintf(repo_version_string, "%d", GIT_REPO_VERSION); + xsnprintf(repo_version_string, sizeof(repo_version_string), + "%d", GIT_REPO_VERSION); git_config_set("core.repositoryformatversion", repo_version_string); - path[len] = 0; - strcpy(path + len, "config"); - /* Check filemode trustability */ + path = git_path_buf(&buf, "config"); filemode = TEST_FILEMODE; if (TEST_FILEMODE && !lstat(path, &st1)) { struct stat st2; @@ -287,15 +253,14 @@ static int create_default_files(const char *template_path) git_config_set("core.bare", "false"); /* allow template config file to override the default */ if (log_all_ref_updates == -1) - git_config_set("core.logallrefupdates", "true"); - if (needs_work_tree_config(git_dir, work_tree)) + git_config_set("core.logallrefupdates", "true"); + if (needs_work_tree_config(get_git_dir(), work_tree)) git_config_set("core.worktree", work_tree); } if (!reinit) { /* Check if symlink is supported in the work tree */ - path[len] = 0; - strcpy(path + len, "tXXXXXX"); + path = git_path_buf(&buf, "tXXXXXX"); if (!close(xmkstemp(path)) && !unlink(path) && !symlink("testing", path) && @@ -306,31 +271,35 @@ static int create_default_files(const char *template_path) git_config_set("core.symlinks", "false"); /* Check if the filesystem is case-insensitive */ - path[len] = 0; - strcpy(path + len, "CoNfIg"); + path = git_path_buf(&buf, "CoNfIg"); if (!access(path, F_OK)) git_config_set("core.ignorecase", "true"); - probe_utf8_pathname_composition(path, len); + probe_utf8_pathname_composition(); } + strbuf_release(&buf); return reinit; } static void create_object_directory(void) { - const char *object_directory = get_object_directory(); - int len = strlen(object_directory); - char *path = xmalloc(len + 40); + struct strbuf path = STRBUF_INIT; + size_t baselen; + + strbuf_addstr(&path, get_object_directory()); + baselen = path.len; + + safe_create_dir(path.buf, 1); - memcpy(path, object_directory, len); + strbuf_setlen(&path, baselen); + strbuf_addstr(&path, "/pack"); + safe_create_dir(path.buf, 1); - safe_create_dir(object_directory, 1); - strcpy(path+len, "/pack"); - safe_create_dir(path, 1); - strcpy(path+len, "/info"); - safe_create_dir(path, 1); + strbuf_setlen(&path, baselen); + strbuf_addstr(&path, "/info"); + safe_create_dir(path.buf, 1); - free(path); + strbuf_release(&path); } int set_git_dir_init(const char *git_dir, const char *real_git_dir, @@ -356,13 +325,13 @@ int set_git_dir_init(const char *git_dir, const char *real_git_dir, set_git_dir(real_path(git_dir)); git_link = NULL; } + startup_info->have_repository = 1; return 0; } static void separate_git_dir(const char *git_dir) { struct stat st; - FILE *fp; if (!stat(git_link, &st)) { const char *src; @@ -378,11 +347,7 @@ static void separate_git_dir(const char *git_dir) die_errno(_("unable to move %s to %s"), src, git_dir); } - fp = fopen(git_link, "w"); - if (!fp) - die(_("Could not create git link %s"), git_link); - fprintf(fp, "gitdir: %s\n", git_dir); - fclose(fp); + write_file(git_link, "gitdir: %s", git_dir); } int init_db(const char *template_dir, unsigned int flags) @@ -408,7 +373,7 @@ int init_db(const char *template_dir, unsigned int flags) 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 @@ -416,15 +381,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 */ - sprintf(buf, "0%o", -shared_repository); - else if (shared_repository == PERM_GROUP) - sprintf(buf, "%d", OLD_PERM_GROUP); - else if (shared_repository == PERM_EVERYBODY) - sprintf(buf, "%d", OLD_PERM_EVERYBODY); + 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 (get_shared_repository() == PERM_EVERYBODY) + xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY); else - die("oops"); + die("BUG: invalid value for shared_repository"); git_config_set("core.sharedrepository", buf); git_config_set("receive.denyNonFastforwards", "true"); } @@ -437,7 +402,7 @@ int init_db(const char *template_dir, unsigned int flags) "", 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") : "", + get_shared_repository() ? _(" shared") : "", git_dir, len && git_dir[len-1] != '/' ? "/" : ""); } @@ -532,8 +497,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: @@ -545,7 +510,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; @@ -563,7 +528,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 |