X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-init-db.c;h=763fa55e76ef5b7e2f244f11199b5925382dac92;hb=8371d8fd094548c1d02b8583fdbff8204a725ffc;hp=235a0ee48f2c5ce09c63a949358eb16cde05332d;hpb=3fbe2d54d7d91378934df7b16d70dc5877586fae;p=git.git diff --git a/builtin-init-db.c b/builtin-init-db.c index 235a0ee48..763fa55e7 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -7,7 +7,13 @@ #include "builtin.h" #ifndef DEFAULT_GIT_TEMPLATE_DIR -#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/" +#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates" +#endif + +#ifdef NO_TRUSTABLE_FILEMODE +#define TEST_FILEMODE 0 +#else +#define TEST_FILEMODE 1 #endif static void safe_create_dir(const char *dir, int share) @@ -34,7 +40,8 @@ static int copy_file(const char *dst, const char *src, int mode) return fdo; } status = copy_fd(fdi, fdo); - close(fdo); + if (close(fdo) != 0) + return error("%s: write error: %s", dst, strerror(errno)); if (!status && adjust_shared_perm(dst)) return -1; @@ -50,7 +57,7 @@ static void copy_templates_1(char *path, int baselen, /* Note: if ".git/hooks" file exists in the repository being * re-initialized, /etc/core-git/templates/hooks/update would - * cause git-init-db to fail here. I think this is sane but + * 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. @@ -124,8 +131,11 @@ static void copy_templates(const char *git_dir, int len, const char *template_di int template_len; DIR *dir; - if (!template_dir) - template_dir = DEFAULT_GIT_TEMPLATE_DIR; + if (!template_dir) { + template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT); + if (!template_dir) + template_dir = DEFAULT_GIT_TEMPLATE_DIR; + } strcpy(template_path, template_dir); template_len = strlen(template_path); if (template_path[template_len-1] != '/') { @@ -164,13 +174,15 @@ static void copy_templates(const char *git_dir, int len, const char *template_di closedir(dir); } -static void create_default_files(const char *git_dir, const char *template_path) +static int create_default_files(const char *git_dir, const char *template_path) { unsigned len = strlen(git_dir); static char path[PATH_MAX]; unsigned char sha1[20]; struct stat st1; char repo_version_string[10]; + int reinit; + int filemode; if (len > sizeof(path)-50) die("insane git directory %s", git_dir); @@ -218,8 +230,9 @@ static void create_default_files(const char *git_dir, const char *template_path) * branch, if it does not exist yet. */ strcpy(path + len, "HEAD"); - if (read_ref("HEAD", sha1) < 0) { - if (create_symref("HEAD", "refs/heads/master") < 0) + reinit = !read_ref("HEAD", sha1); + if (!reinit) { + if (create_symref("HEAD", "refs/heads/master", NULL) < 0) exit(1); } @@ -231,18 +244,84 @@ static void create_default_files(const char *git_dir, const char *template_path) strcpy(path + len, "config"); /* Check filemode trustability */ - if (!lstat(path, &st1)) { + filemode = TEST_FILEMODE; + if (TEST_FILEMODE && !lstat(path, &st1)) { struct stat st2; - int filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) && + filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) && !lstat(path, &st2) && st1.st_mode != st2.st_mode); - git_config_set("core.filemode", - filemode ? "true" : "false"); } + git_config_set("core.filemode", filemode ? "true" : "false"); + + if (is_bare_repository()) + git_config_set("core.bare", "true"); + else { + 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) + git_config_set("core.logallrefupdates", "true"); + if (work_tree != git_work_tree_cfg) + git_config_set("core.worktree", work_tree); + } + + /* Check if symlink is supported in the work tree */ + if (!reinit) { + path[len] = 0; + strcpy(path + len, "tXXXXXX"); + if (!close(xmkstemp(path)) && + !unlink(path) && + !symlink("testing", path) && + !lstat(path, &st1) && + S_ISLNK(st1.st_mode)) + unlink(path); /* good */ + else + git_config_set("core.symlinks", "false"); + } + + return reinit; +} + +static void guess_repository_type(const char *git_dir) +{ + char cwd[PATH_MAX]; + const char *slash; + + if (0 <= is_bare_repository_cfg) + return; + if (!git_dir) + return; + + /* + * "GIT_DIR=. git init" is always bare. + * "GIT_DIR=`pwd` git init" too. + */ + if (!strcmp(".", git_dir)) + goto force_bare; + if (!getcwd(cwd, sizeof(cwd))) + die("cannot tell cwd"); + if (!strcmp(git_dir, cwd)) + goto force_bare; + /* + * "GIT_DIR=.git or GIT_DIR=something/.git is usually not. + */ + if (!strcmp(git_dir, ".git")) + return; + slash = strrchr(git_dir, '/'); + if (slash && !strcmp(slash, "/.git")) + return; + + /* + * Otherwise it is often bare. At this point + * we are just guessing. + */ + force_bare: + is_bare_repository_cfg = 1; + return; } static const char init_db_usage[] = -"git-init-db [--template=] [--shared]"; +"git-init [-q | --quiet] [--template=] [--shared]"; /* * If you want to, you can share the DB area with any number of branches. @@ -256,28 +335,52 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) const char *sha1_dir; const char *template_dir = NULL; char *path; - int len, i; + int len, i, reinit; + int quiet = 0; for (i = 1; i < argc; i++, argv++) { const char *arg = argv[1]; - if (!strncmp(arg, "--template=", 11)) + if (!prefixcmp(arg, "--template=")) template_dir = arg+11; else if (!strcmp(arg, "--shared")) shared_repository = PERM_GROUP; - else if (!strncmp(arg, "--shared=", 9)) + else if (!prefixcmp(arg, "--shared=")) shared_repository = git_config_perm("arg", arg+9); + else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet")) + quiet = 1; else usage(init_db_usage); } + /* + * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR + * without --bare. Catch the error early. + */ + git_dir = getenv(GIT_DIR_ENVIRONMENT); + if ((!git_dir || is_bare_repository_cfg == 1) + && getenv(GIT_WORK_TREE_ENVIRONMENT)) + die("%s (or --work-tree=) not allowed without " + "specifying %s (or --git-dir=)", + GIT_WORK_TREE_ENVIRONMENT, + GIT_DIR_ENVIRONMENT); + + guess_repository_type(git_dir); + + if (is_bare_repository_cfg <= 0) { + git_work_tree_cfg = xcalloc(PATH_MAX, 1); + if (!getcwd(git_work_tree_cfg, PATH_MAX)) + die ("Cannot access current working directory."); + if (access(get_git_work_tree(), X_OK)) + die ("Cannot access work tree '%s'", + get_git_work_tree()); + } + /* * Set up the default .git directory contents */ git_dir = getenv(GIT_DIR_ENVIRONMENT); - if (!git_dir) { + if (!git_dir) git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; - fprintf(stderr, "defaulting to local storage area\n"); - } safe_create_dir(git_dir, 0); /* Check to see if the repository version is right. @@ -287,7 +390,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) */ check_repository_format(); - create_default_files(git_dir, template_dir); + reinit = create_default_files(git_dir, template_dir); /* * And set up the object store. @@ -314,5 +417,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) git_config_set("receive.denyNonFastforwards", "true"); } + if (!quiet) + printf("%s%s Git repository in %s/\n", + reinit ? "Reinitialized existing" : "Initialized empty", + shared_repository ? " shared" : "", + git_dir); + return 0; }