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