Linus Torvalds | 8bc9a0c | 2005-04-07 15:16:10 -0700 | [diff] [blame] | 1 | /* |
| 2 | * GIT - The information manager from hell |
| 3 | * |
| 4 | * Copyright (C) Linus Torvalds, 2005 |
| 5 | */ |
Linus Torvalds | e83c516 | 2005-04-07 15:13:13 -0700 | [diff] [blame] | 6 | #include "cache.h" |
| 7 | |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 8 | #ifndef DEFAULT_GIT_TEMPLATE_DIR |
| 9 | #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/" |
| 10 | #endif |
| 11 | |
Linus Torvalds | e99d59f | 2005-05-20 11:46:10 -0700 | [diff] [blame] | 12 | static void safe_create_dir(const char *dir) |
Zach Welch | cb126d8 | 2005-04-19 21:48:15 -0700 | [diff] [blame] | 13 | { |
Junio C Hamano | f312de0 | 2005-07-06 01:21:46 -0700 | [diff] [blame] | 14 | if (mkdir(dir, 0777) < 0) { |
Zach Welch | cb126d8 | 2005-04-19 21:48:15 -0700 | [diff] [blame] | 15 | if (errno != EEXIST) { |
| 16 | perror(dir); |
| 17 | exit(1); |
| 18 | } |
| 19 | } |
| 20 | } |
| 21 | |
Junio C Hamano | 8d5afef | 2005-08-02 16:45:21 -0700 | [diff] [blame] | 22 | static int copy_file(const char *dst, const char *src, int mode) |
| 23 | { |
Junio C Hamano | 32276c8 | 2005-11-05 11:07:22 -0800 | [diff] [blame] | 24 | int fdi, fdo, status; |
Junio C Hamano | 8d5afef | 2005-08-02 16:45:21 -0700 | [diff] [blame] | 25 | |
| 26 | mode = (mode & 0111) ? 0777 : 0666; |
| 27 | if ((fdi = open(src, O_RDONLY)) < 0) |
| 28 | return fdi; |
| 29 | if ((fdo = open(dst, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) { |
| 30 | close(fdi); |
| 31 | return fdo; |
| 32 | } |
Junio C Hamano | 32276c8 | 2005-11-05 11:07:22 -0800 | [diff] [blame] | 33 | status = copy_fd(fdi, fdo); |
Junio C Hamano | 8d5afef | 2005-08-02 16:45:21 -0700 | [diff] [blame] | 34 | close(fdo); |
Junio C Hamano | 32276c8 | 2005-11-05 11:07:22 -0800 | [diff] [blame] | 35 | return status; |
Junio C Hamano | 8d5afef | 2005-08-02 16:45:21 -0700 | [diff] [blame] | 36 | } |
| 37 | |
| 38 | static void copy_templates_1(char *path, int baselen, |
| 39 | char *template, int template_baselen, |
| 40 | DIR *dir) |
| 41 | { |
| 42 | struct dirent *de; |
| 43 | |
| 44 | /* Note: if ".git/hooks" file exists in the repository being |
| 45 | * re-initialized, /etc/core-git/templates/hooks/update would |
| 46 | * cause git-init-db to fail here. I think this is sane but |
| 47 | * it means that the set of templates we ship by default, along |
| 48 | * with the way the namespace under .git/ is organized, should |
| 49 | * be really carefully chosen. |
| 50 | */ |
| 51 | safe_create_dir(path); |
| 52 | while ((de = readdir(dir)) != NULL) { |
| 53 | struct stat st_git, st_template; |
| 54 | int namelen; |
| 55 | int exists = 0; |
| 56 | |
| 57 | if (de->d_name[0] == '.') |
| 58 | continue; |
| 59 | namelen = strlen(de->d_name); |
| 60 | if ((PATH_MAX <= baselen + namelen) || |
| 61 | (PATH_MAX <= template_baselen + namelen)) |
| 62 | die("insanely long template name %s", de->d_name); |
| 63 | memcpy(path + baselen, de->d_name, namelen+1); |
| 64 | memcpy(template + template_baselen, de->d_name, namelen+1); |
| 65 | if (lstat(path, &st_git)) { |
| 66 | if (errno != ENOENT) |
| 67 | die("cannot stat %s", path); |
| 68 | } |
| 69 | else |
| 70 | exists = 1; |
| 71 | |
| 72 | if (lstat(template, &st_template)) |
| 73 | die("cannot stat template %s", template); |
| 74 | |
| 75 | if (S_ISDIR(st_template.st_mode)) { |
| 76 | DIR *subdir = opendir(template); |
| 77 | int baselen_sub = baselen + namelen; |
| 78 | int template_baselen_sub = template_baselen + namelen; |
| 79 | if (!subdir) |
| 80 | die("cannot opendir %s", template); |
| 81 | path[baselen_sub++] = |
| 82 | template[template_baselen_sub++] = '/'; |
| 83 | path[baselen_sub] = |
| 84 | template[template_baselen_sub] = 0; |
| 85 | copy_templates_1(path, baselen_sub, |
| 86 | template, template_baselen_sub, |
| 87 | subdir); |
| 88 | closedir(subdir); |
| 89 | } |
| 90 | else if (exists) |
| 91 | continue; |
| 92 | else if (S_ISLNK(st_template.st_mode)) { |
| 93 | char lnk[256]; |
| 94 | int len; |
| 95 | len = readlink(template, lnk, sizeof(lnk)); |
| 96 | if (len < 0) |
| 97 | die("cannot readlink %s", template); |
| 98 | if (sizeof(lnk) <= len) |
| 99 | die("insanely long symlink %s", template); |
| 100 | lnk[len] = 0; |
| 101 | if (symlink(lnk, path)) |
| 102 | die("cannot symlink %s %s", lnk, path); |
| 103 | } |
| 104 | else if (S_ISREG(st_template.st_mode)) { |
| 105 | if (copy_file(path, template, st_template.st_mode)) |
| 106 | die("cannot copy %s to %s", template, path); |
| 107 | } |
| 108 | else |
| 109 | error("ignoring template %s", template); |
| 110 | } |
| 111 | } |
| 112 | |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 113 | static void copy_templates(const char *git_dir, int len, char *template_dir) |
Junio C Hamano | 8d5afef | 2005-08-02 16:45:21 -0700 | [diff] [blame] | 114 | { |
| 115 | char path[PATH_MAX]; |
| 116 | char template_path[PATH_MAX]; |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 117 | int template_len; |
Junio C Hamano | 8d5afef | 2005-08-02 16:45:21 -0700 | [diff] [blame] | 118 | DIR *dir; |
| 119 | |
Junio C Hamano | 8d5afef | 2005-08-02 16:45:21 -0700 | [diff] [blame] | 120 | if (!template_dir) |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 121 | template_dir = DEFAULT_GIT_TEMPLATE_DIR; |
Junio C Hamano | 8d5afef | 2005-08-02 16:45:21 -0700 | [diff] [blame] | 122 | strcpy(template_path, template_dir); |
| 123 | template_len = strlen(template_path); |
| 124 | if (template_path[template_len-1] != '/') { |
| 125 | template_path[template_len++] = '/'; |
| 126 | template_path[template_len] = 0; |
| 127 | } |
Junio C Hamano | 8d5afef | 2005-08-02 16:45:21 -0700 | [diff] [blame] | 128 | dir = opendir(template_path); |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 129 | if (!dir) { |
| 130 | fprintf(stderr, "warning: templates not found %s\n", |
| 131 | template_dir); |
Junio C Hamano | 8d5afef | 2005-08-02 16:45:21 -0700 | [diff] [blame] | 132 | return; |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 133 | } |
| 134 | |
Junio C Hamano | 4f62953 | 2005-11-25 16:03:56 -0800 | [diff] [blame] | 135 | /* Make sure that template is from the correct vintage */ |
| 136 | strcpy(template_path + template_len, "config"); |
| 137 | repository_format_version = 0; |
| 138 | git_config_from_file(check_repository_format_version, |
| 139 | template_path); |
| 140 | template_path[template_len] = 0; |
| 141 | |
| 142 | if (repository_format_version && |
| 143 | repository_format_version != GIT_REPO_VERSION) { |
| 144 | fprintf(stderr, "warning: not copying templates of " |
| 145 | "a wrong format version %d from '%s'\n", |
| 146 | repository_format_version, |
| 147 | template_dir); |
| 148 | closedir(dir); |
| 149 | return; |
| 150 | } |
| 151 | |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 152 | memcpy(path, git_dir, len); |
Petr Baudis | 1f961c1 | 2005-09-20 02:19:50 +0200 | [diff] [blame] | 153 | path[len] = 0; |
Junio C Hamano | 8d5afef | 2005-08-02 16:45:21 -0700 | [diff] [blame] | 154 | copy_templates_1(path, len, |
| 155 | template_path, template_len, |
| 156 | dir); |
| 157 | closedir(dir); |
| 158 | } |
| 159 | |
Junio C Hamano | 4f62953 | 2005-11-25 16:03:56 -0800 | [diff] [blame] | 160 | static void create_default_files(const char *git_dir, char *template_path) |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 161 | { |
| 162 | unsigned len = strlen(git_dir); |
| 163 | static char path[PATH_MAX]; |
Junio C Hamano | 8098a17 | 2005-09-30 14:26:57 -0700 | [diff] [blame] | 164 | unsigned char sha1[20]; |
Junio C Hamano | 4f62953 | 2005-11-25 16:03:56 -0800 | [diff] [blame] | 165 | struct stat st1; |
| 166 | char repo_version_string[10]; |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 167 | |
| 168 | if (len > sizeof(path)-50) |
| 169 | die("insane git directory %s", git_dir); |
| 170 | memcpy(path, git_dir, len); |
| 171 | |
| 172 | if (len && path[len-1] != '/') |
| 173 | path[len++] = '/'; |
| 174 | |
| 175 | /* |
| 176 | * Create .git/refs/{heads,tags} |
| 177 | */ |
| 178 | strcpy(path + len, "refs"); |
| 179 | safe_create_dir(path); |
| 180 | strcpy(path + len, "refs/heads"); |
| 181 | safe_create_dir(path); |
| 182 | strcpy(path + len, "refs/tags"); |
| 183 | safe_create_dir(path); |
| 184 | |
Junio C Hamano | 4f62953 | 2005-11-25 16:03:56 -0800 | [diff] [blame] | 185 | /* First copy the templates -- we might have the default |
| 186 | * config file there, in which case we would want to read |
| 187 | * from it after installing. |
| 188 | */ |
| 189 | path[len] = 0; |
| 190 | copy_templates(path, len, template_path); |
| 191 | |
| 192 | git_config(git_default_config); |
| 193 | |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 194 | /* |
| 195 | * Create the default symlink from ".git/HEAD" to the "master" |
Junio C Hamano | 8098a17 | 2005-09-30 14:26:57 -0700 | [diff] [blame] | 196 | * branch, if it does not exist yet. |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 197 | */ |
| 198 | strcpy(path + len, "HEAD"); |
Junio C Hamano | 8098a17 | 2005-09-30 14:26:57 -0700 | [diff] [blame] | 199 | if (read_ref(path, sha1) < 0) { |
| 200 | if (create_symref(path, "refs/heads/master") < 0) |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 201 | exit(1); |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 202 | } |
Junio C Hamano | 4f62953 | 2005-11-25 16:03:56 -0800 | [diff] [blame] | 203 | |
| 204 | /* This forces creation of new config file */ |
| 205 | sprintf(repo_version_string, "%d", GIT_REPO_VERSION); |
| 206 | git_config_set("core.repositoryformatversion", repo_version_string); |
| 207 | |
Junio C Hamano | 8098a17 | 2005-09-30 14:26:57 -0700 | [diff] [blame] | 208 | path[len] = 0; |
Johannes Schindelin | e24317b | 2005-10-26 01:43:03 +0200 | [diff] [blame] | 209 | strcpy(path + len, "config"); |
Johannes Schindelin | e24317b | 2005-10-26 01:43:03 +0200 | [diff] [blame] | 210 | |
Junio C Hamano | 4f62953 | 2005-11-25 16:03:56 -0800 | [diff] [blame] | 211 | /* Check filemode trustability */ |
| 212 | if (!lstat(path, &st1)) { |
| 213 | struct stat st2; |
| 214 | int filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) && |
| 215 | !lstat(path, &st2) && |
| 216 | st1.st_mode != st2.st_mode); |
| 217 | git_config_set("core.filemode", |
| 218 | filemode ? "true" : "false"); |
Johannes Schindelin | e24317b | 2005-10-26 01:43:03 +0200 | [diff] [blame] | 219 | } |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 220 | } |
| 221 | |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 222 | static const char init_db_usage[] = |
| 223 | "git-init-db [--template=<template-directory>]"; |
| 224 | |
Zach Welch | 4696cb9 | 2005-04-19 21:48:15 -0700 | [diff] [blame] | 225 | /* |
| 226 | * If you want to, you can share the DB area with any number of branches. |
| 227 | * That has advantages: you can save space by sharing all the SHA1 objects. |
| 228 | * On the other hand, it might just make lookup slower and messier. You |
| 229 | * be the judge. The default case is to have one DB per managed directory. |
| 230 | */ |
Linus Torvalds | e83c516 | 2005-04-07 15:13:13 -0700 | [diff] [blame] | 231 | int main(int argc, char **argv) |
| 232 | { |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 233 | const char *git_dir; |
Junio C Hamano | d19938a | 2005-05-09 17:57:56 -0700 | [diff] [blame] | 234 | const char *sha1_dir; |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 235 | char *path, *template_dir = NULL; |
Linus Torvalds | 19b2860 | 2005-04-08 09:59:28 -0700 | [diff] [blame] | 236 | int len, i; |
Linus Torvalds | e83c516 | 2005-04-07 15:13:13 -0700 | [diff] [blame] | 237 | |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 238 | for (i = 1; i < argc; i++, argv++) { |
| 239 | char *arg = argv[1]; |
Junio C Hamano | 4a62eae | 2005-12-05 22:29:36 -0800 | [diff] [blame] | 240 | if (!strncmp(arg, "--template=", 11)) |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 241 | template_dir = arg+11; |
| 242 | else |
| 243 | die(init_db_usage); |
| 244 | } |
| 245 | |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 246 | /* |
| 247 | * Set up the default .git directory contents |
| 248 | */ |
Junio C Hamano | a9ab586 | 2005-09-09 14:48:54 -0700 | [diff] [blame] | 249 | git_dir = getenv(GIT_DIR_ENVIRONMENT); |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 250 | if (!git_dir) { |
| 251 | git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; |
Zach Welch | addb315 | 2005-04-19 21:48:15 -0700 | [diff] [blame] | 252 | fprintf(stderr, "defaulting to local storage area\n"); |
Linus Torvalds | e83c516 | 2005-04-07 15:13:13 -0700 | [diff] [blame] | 253 | } |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 254 | safe_create_dir(git_dir); |
Junio C Hamano | 4f62953 | 2005-11-25 16:03:56 -0800 | [diff] [blame] | 255 | |
| 256 | /* Check to see if the repository version is right. |
| 257 | * Note that a newly created repository does not have |
| 258 | * config file, so this will not fail. What we are catching |
| 259 | * is an attempt to reinitialize new repository with an old tool. |
| 260 | */ |
| 261 | check_repository_format(); |
| 262 | |
Junio C Hamano | d3af621 | 2005-08-06 12:50:14 -0700 | [diff] [blame] | 263 | create_default_files(git_dir, template_dir); |
Linus Torvalds | cad88fd | 2005-05-30 10:20:44 -0700 | [diff] [blame] | 264 | |
| 265 | /* |
| 266 | * And set up the object store. |
| 267 | */ |
| 268 | sha1_dir = get_object_directory(); |
Linus Torvalds | e83c516 | 2005-04-07 15:13:13 -0700 | [diff] [blame] | 269 | len = strlen(sha1_dir); |
Christopher Li | 812666c | 2005-04-26 12:00:58 -0700 | [diff] [blame] | 270 | path = xmalloc(len + 40); |
Linus Torvalds | e83c516 | 2005-04-07 15:13:13 -0700 | [diff] [blame] | 271 | memcpy(path, sha1_dir, len); |
Zach Welch | cb126d8 | 2005-04-19 21:48:15 -0700 | [diff] [blame] | 272 | |
| 273 | safe_create_dir(sha1_dir); |
Linus Torvalds | f49fb35 | 2005-06-27 18:26:11 -0700 | [diff] [blame] | 274 | strcpy(path+len, "/pack"); |
| 275 | safe_create_dir(path); |
Junio C Hamano | d57306c | 2005-08-20 02:05:31 -0700 | [diff] [blame] | 276 | strcpy(path+len, "/info"); |
| 277 | safe_create_dir(path); |
Linus Torvalds | e83c516 | 2005-04-07 15:13:13 -0700 | [diff] [blame] | 278 | return 0; |
| 279 | } |