1/*2* GIT - The information manager from hell3*4* Copyright (C) Linus Torvalds, 20055*/6#include "cache.h"78static void safe_create_dir(const char *dir)9{10if (mkdir(dir, 0777) < 0) {11if (errno != EEXIST) {12perror(dir);13exit(1);14}15}16}1718static int copy_file(const char *dst, const char *src, int mode)19{20int fdi, fdo;2122mode = (mode & 0111) ? 0777 : 0666;23if ((fdi = open(src, O_RDONLY)) < 0)24return fdi;25if ((fdo = open(dst, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) {26close(fdi);27return fdo;28}29while (1) {30char buf[BUFSIZ];31ssize_t leni, leno, ofs;32leni = read(fdi, buf, sizeof(buf));33if (leni < 0) {34error_return:35close(fdo);36close(fdi);37return -1;38}39if (!leni)40break;41ofs = 0;42do {43leno = write(fdo, buf+ofs, leni);44if (leno < 0)45goto error_return;46leni -= leno;47ofs += leno;48} while (0 < leni);49}50close(fdo);51close(fdi);52return 0;53}5455static void copy_templates_1(char *path, int baselen,56char *template, int template_baselen,57DIR *dir)58{59struct dirent *de;6061/* Note: if ".git/hooks" file exists in the repository being62* re-initialized, /etc/core-git/templates/hooks/update would63* cause git-init-db to fail here. I think this is sane but64* it means that the set of templates we ship by default, along65* with the way the namespace under .git/ is organized, should66* be really carefully chosen.67*/68safe_create_dir(path);69while ((de = readdir(dir)) != NULL) {70struct stat st_git, st_template;71int namelen;72int exists = 0;7374if (de->d_name[0] == '.')75continue;76namelen = strlen(de->d_name);77if ((PATH_MAX <= baselen + namelen) ||78(PATH_MAX <= template_baselen + namelen))79die("insanely long template name %s", de->d_name);80memcpy(path + baselen, de->d_name, namelen+1);81memcpy(template + template_baselen, de->d_name, namelen+1);82if (lstat(path, &st_git)) {83if (errno != ENOENT)84die("cannot stat %s", path);85}86else87exists = 1;8889if (lstat(template, &st_template))90die("cannot stat template %s", template);9192if (S_ISDIR(st_template.st_mode)) {93DIR *subdir = opendir(template);94int baselen_sub = baselen + namelen;95int template_baselen_sub = template_baselen + namelen;96if (!subdir)97die("cannot opendir %s", template);98path[baselen_sub++] =99template[template_baselen_sub++] = '/';100path[baselen_sub] =101template[template_baselen_sub] = 0;102copy_templates_1(path, baselen_sub,103template, template_baselen_sub,104subdir);105closedir(subdir);106}107else if (exists)108continue;109else if (S_ISLNK(st_template.st_mode)) {110char lnk[256];111int len;112len = readlink(template, lnk, sizeof(lnk));113if (len < 0)114die("cannot readlink %s", template);115if (sizeof(lnk) <= len)116die("insanely long symlink %s", template);117lnk[len] = 0;118if (symlink(lnk, path))119die("cannot symlink %s %s", lnk, path);120}121else if (S_ISREG(st_template.st_mode)) {122if (copy_file(path, template, st_template.st_mode))123die("cannot copy %s to %s", template, path);124}125else126error("ignoring template %s", template);127}128}129130static void copy_templates(const char *git_dir)131{132char path[PATH_MAX];133char template_path[PATH_MAX];134char *template_dir;135int len, template_len;136DIR *dir;137138strcpy(path, git_dir);139len = strlen(path);140template_dir = gitenv(TEMPLATE_DIR_ENVIRONMENT);141if (!template_dir)142template_dir = DEFAULT_GIT_TEMPLATE_ENVIRONMENT;143strcpy(template_path, template_dir);144template_len = strlen(template_path);145if (template_path[template_len-1] != '/') {146template_path[template_len++] = '/';147template_path[template_len] = 0;148}149150dir = opendir(template_path);151if (!dir)152return;153copy_templates_1(path, len,154template_path, template_len,155dir);156closedir(dir);157}158159static void create_default_files(const char *git_dir)160{161unsigned len = strlen(git_dir);162static char path[PATH_MAX];163164if (len > sizeof(path)-50)165die("insane git directory %s", git_dir);166memcpy(path, git_dir, len);167168if (len && path[len-1] != '/')169path[len++] = '/';170171/*172* Create .git/refs/{heads,tags}173*/174strcpy(path + len, "refs");175safe_create_dir(path);176strcpy(path + len, "refs/heads");177safe_create_dir(path);178strcpy(path + len, "refs/tags");179safe_create_dir(path);180181/*182* Create the default symlink from ".git/HEAD" to the "master"183* branch184*/185strcpy(path + len, "HEAD");186if (symlink("refs/heads/master", path) < 0) {187if (errno != EEXIST) {188perror(path);189exit(1);190}191}192path[len] = 0;193copy_templates(path);194}195196/*197* If you want to, you can share the DB area with any number of branches.198* That has advantages: you can save space by sharing all the SHA1 objects.199* On the other hand, it might just make lookup slower and messier. You200* be the judge. The default case is to have one DB per managed directory.201*/202int main(int argc, char **argv)203{204const char *git_dir;205const char *sha1_dir;206char *path;207int len, i;208209/*210* Set up the default .git directory contents211*/212git_dir = gitenv(GIT_DIR_ENVIRONMENT);213if (!git_dir) {214git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;215fprintf(stderr, "defaulting to local storage area\n");216}217safe_create_dir(git_dir);218create_default_files(git_dir);219220/*221* And set up the object store.222*/223sha1_dir = get_object_directory();224len = strlen(sha1_dir);225path = xmalloc(len + 40);226memcpy(path, sha1_dir, len);227228safe_create_dir(sha1_dir);229for (i = 0; i < 256; i++) {230sprintf(path+len, "/%02x", i);231safe_create_dir(path);232}233strcpy(path+len, "/pack");234safe_create_dir(path);235return 0;236}