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 = REPOSITORY_FORMAT_INIT; struct strbuf err = STRBUF_INIT; DIR *dir; char *to_free = NULL; if (!template_dir) template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT); if (!template_dir) template_dir = init_db_template_dir; if (!template_dir) template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR); if (!template_dir[0]) { free(to_free); return; } 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 in %s"), template_dir); goto free_return; } /* Make sure that template is from the correct vintage */ 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; } strbuf_addstr(&path, get_git_common_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); clear_repository_format(&template_format); }
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_path->len; struct dirent *de; /* Note: if ".git/hooks" file exists in the repository being * re-initialized, /etc/core-git/templates/hooks/update would * cause "git init" to fail here. I think this is sane but * it means that the set of templates we ship by default, along * with the way the namespace under .git/ is organized, should * be really carefully chosen. */ safe_create_dir(path->buf, 1); while ((de = readdir(dir)) != NULL) { struct stat st_git, st_template; int exists = 0; strbuf_setlen(path, path_baselen); strbuf_setlen(template_path, template_baselen); if (de->d_name[0] == '.') continue; strbuf_addstr(path, 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); } else exists = 1; 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_path->buf); if (!subdir) die_errno(_("cannot opendir '%s'"), template_path->buf); strbuf_addch(path, '/'); 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_path->buf, st_template.st_size) < 0) die_errno(_("cannot readlink '%s'"), template_path->buf); if (create_symlink(NULL, 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_path->buf, st_template.st_mode)) die_errno(_("cannot copy '%s' to '%s'"), template_path->buf, path->buf); } else error(_("ignoring template %s"), template_path->buf); } }