51e354ca0760d8b6593fe50720b47c160dd8fe59
1#include "cache.h"
2#include "dir.h"
3
4static int inside_git_dir = -1;
5static int inside_work_tree = -1;
6
7char *prefix_path(const char *prefix, int len, const char *path)
8{
9 const char *orig = path;
10 char *sanitized;
11 if (is_absolute_path(orig)) {
12 const char *temp = real_path(path);
13 sanitized = xmalloc(len + strlen(temp) + 1);
14 strcpy(sanitized, temp);
15 } else {
16 sanitized = xmalloc(len + strlen(path) + 1);
17 if (len)
18 memcpy(sanitized, prefix, len);
19 strcpy(sanitized + len, path);
20 }
21 if (normalize_path_copy(sanitized, sanitized))
22 goto error_out;
23 if (is_absolute_path(orig)) {
24 size_t root_len, len, total;
25 const char *work_tree = get_git_work_tree();
26 if (!work_tree)
27 goto error_out;
28 len = strlen(work_tree);
29 root_len = offset_1st_component(work_tree);
30 total = strlen(sanitized) + 1;
31 if (strncmp(sanitized, work_tree, len) ||
32 (len > root_len && sanitized[len] != '\0' && sanitized[len] != '/')) {
33 error_out:
34 die("'%s' is outside repository", orig);
35 }
36 if (sanitized[len] == '/')
37 len++;
38 memmove(sanitized, sanitized + len, total - len);
39 }
40 return sanitized;
41}
42
43/*
44 * Unlike prefix_path, this should be used if the named file does
45 * not have to interact with index entry; i.e. name of a random file
46 * on the filesystem.
47 */
48const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
49{
50 static char path[PATH_MAX];
51#ifndef WIN32
52 if (!pfx_len || is_absolute_path(arg))
53 return arg;
54 memcpy(path, pfx, pfx_len);
55 strcpy(path + pfx_len, arg);
56#else
57 char *p;
58 /* don't add prefix to absolute paths, but still replace '\' by '/' */
59 if (is_absolute_path(arg))
60 pfx_len = 0;
61 else if (pfx_len)
62 memcpy(path, pfx, pfx_len);
63 strcpy(path + pfx_len, arg);
64 for (p = path + pfx_len; *p; p++)
65 if (*p == '\\')
66 *p = '/';
67#endif
68 return path;
69}
70
71int check_filename(const char *prefix, const char *arg)
72{
73 const char *name;
74 struct stat st;
75
76 name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
77 if (!lstat(name, &st))
78 return 1; /* file exists */
79 if (errno == ENOENT || errno == ENOTDIR)
80 return 0; /* file does not exist */
81 die_errno("failed to stat '%s'", arg);
82}
83
84static void NORETURN die_verify_filename(const char *prefix, const char *arg)
85{
86 unsigned char sha1[20];
87 unsigned mode;
88 /* try a detailed diagnostic ... */
89 get_sha1_with_mode_1(arg, sha1, &mode, 0, prefix);
90 /* ... or fall back the most general message. */
91 die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
92 "Use '--' to separate paths from revisions", arg);
93
94}
95
96/*
97 * Verify a filename that we got as an argument for a pathspec
98 * entry. Note that a filename that begins with "-" never verifies
99 * as true, because even if such a filename were to exist, we want
100 * it to be preceded by the "--" marker (or we want the user to
101 * use a format like "./-filename")
102 */
103void verify_filename(const char *prefix, const char *arg)
104{
105 if (*arg == '-')
106 die("bad flag '%s' used after filename", arg);
107 if (check_filename(prefix, arg))
108 return;
109 die_verify_filename(prefix, arg);
110}
111
112/*
113 * Opposite of the above: the command line did not have -- marker
114 * and we parsed the arg as a refname. It should not be interpretable
115 * as a filename.
116 */
117void verify_non_filename(const char *prefix, const char *arg)
118{
119 if (!is_inside_work_tree() || is_inside_git_dir())
120 return;
121 if (*arg == '-')
122 return; /* flag */
123 if (!check_filename(prefix, arg))
124 return;
125 die("ambiguous argument '%s': both revision and filename\n"
126 "Use '--' to separate filenames from revisions", arg);
127}
128
129/*
130 * Magic pathspec
131 *
132 * NEEDSWORK: These need to be moved to dir.h or even to a new
133 * pathspec.h when we restructure get_pathspec() users to use the
134 * "struct pathspec" interface.
135 *
136 * Possible future magic semantics include stuff like:
137 *
138 * { PATHSPEC_NOGLOB, '!', "noglob" },
139 * { PATHSPEC_RECURSIVE, '*', "recursive" },
140 * { PATHSPEC_REGEXP, '\0', "regexp" },
141 *
142 */
143#define PATHSPEC_FROMTOP (1<<0)
144#define PATHSPEC_ICASE (1<<1)
145
146struct pathspec_magic {
147 unsigned bit;
148 char mnemonic; /* this cannot be ':'! */
149 const char *name;
150} pathspec_magic[] = {
151 { PATHSPEC_FROMTOP, '/', "top" },
152 { PATHSPEC_ICASE, '\0', "icase" },
153};
154
155/*
156 * Take an element of a pathspec and check for magic signatures.
157 * Append the result to the prefix.
158 *
159 * For now, we only parse the syntax and throw out anything other than
160 * "top" magic.
161 *
162 * NEEDSWORK: This needs to be rewritten when we start migrating
163 * get_pathspec() users to use the "struct pathspec" interface. For
164 * example, a pathspec element may be marked as case-insensitive, but
165 * the prefix part must always match literally, and a single stupid
166 * string cannot express such a case.
167 */
168const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)
169{
170 unsigned magic = 0;
171 const char *copyfrom = elt;
172 const char *retval;
173 int i, free_source = 0;
174
175 if (elt[0] != ':') {
176 ; /* nothing to do */
177 } else if (elt[1] == '(') {
178 /* longhand */
179 const char *nextat;
180 for (copyfrom = elt + 2;
181 *copyfrom && *copyfrom != ')';
182 copyfrom = nextat) {
183 size_t len = strcspn(copyfrom, ",)");
184 if (copyfrom[len] == ')')
185 nextat = copyfrom + len;
186 else
187 nextat = copyfrom + len + 1;
188 if (!len)
189 continue;
190 for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
191 if (strlen(pathspec_magic[i].name) == len &&
192 !strncmp(pathspec_magic[i].name, copyfrom, len)) {
193 magic |= pathspec_magic[i].bit;
194 break;
195 }
196 if (ARRAY_SIZE(pathspec_magic) <= i)
197 die("Invalid pathspec magic '%.*s' in '%s'",
198 (int) len, copyfrom, elt);
199 }
200 if (*copyfrom == ')')
201 copyfrom++;
202 } else if (!elt[1]) {
203 /* Just ':' -- no element! */
204 return NULL;
205 } else {
206 /* shorthand */
207 for (copyfrom = elt + 1;
208 *copyfrom && *copyfrom != ':';
209 copyfrom++) {
210 char ch = *copyfrom;
211
212 if (!is_pathspec_magic(ch))
213 break;
214 for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
215 if (pathspec_magic[i].mnemonic == ch) {
216 magic |= pathspec_magic[i].bit;
217 break;
218 }
219 if (ARRAY_SIZE(pathspec_magic) <= i)
220 die("Unimplemented pathspec magic '%c' in '%s'",
221 ch, elt);
222 }
223 if (*copyfrom == ':')
224 copyfrom++;
225 }
226
227 if (magic & PATHSPEC_ICASE) {
228 struct strbuf sb = STRBUF_INIT;
229 for (i = 0; copyfrom[i]; i++) {
230 int ch = copyfrom[i];
231 if (('a' <= ch && ch <= 'z') ||
232 ('A' <= ch && ch <= 'Z')) {
233 strbuf_addf(&sb, "[%c%c]",
234 tolower(ch), toupper(ch));
235 } else {
236 strbuf_addch(&sb, ch);
237 }
238 }
239 if (sb.len) {
240 free_source = 1;
241 copyfrom = strbuf_detach(&sb, NULL);
242 }
243 }
244
245 if (magic & PATHSPEC_FROMTOP)
246 retval = xstrdup(copyfrom);
247 else
248 retval = prefix_path(prefix, prefixlen, copyfrom);
249 if (free_source)
250 free((char *)copyfrom);
251 return retval;
252}
253
254const char **get_pathspec(const char *prefix, const char **pathspec)
255{
256 const char *entry = *pathspec;
257 const char **src, **dst;
258 int prefixlen;
259
260 if (!prefix && !entry)
261 return NULL;
262
263 if (!entry) {
264 static const char *spec[2];
265 spec[0] = prefix;
266 spec[1] = NULL;
267 return spec;
268 }
269
270 /* Otherwise we have to re-write the entries.. */
271 src = pathspec;
272 dst = pathspec;
273 prefixlen = prefix ? strlen(prefix) : 0;
274 while (*src) {
275 *(dst++) = prefix_pathspec(prefix, prefixlen, *src);
276 src++;
277 }
278 *dst = NULL;
279 if (!*pathspec)
280 return NULL;
281 return pathspec;
282}
283
284/*
285 * Test if it looks like we're at a git directory.
286 * We want to see:
287 *
288 * - either an objects/ directory _or_ the proper
289 * GIT_OBJECT_DIRECTORY environment variable
290 * - a refs/ directory
291 * - either a HEAD symlink or a HEAD file that is formatted as
292 * a proper "ref:", or a regular file HEAD that has a properly
293 * formatted sha1 object name.
294 */
295static int is_git_directory(const char *suspect)
296{
297 char path[PATH_MAX];
298 size_t len = strlen(suspect);
299
300 if (PATH_MAX <= len + strlen("/objects"))
301 die("Too long path: %.*s", 60, suspect);
302 strcpy(path, suspect);
303 if (getenv(DB_ENVIRONMENT)) {
304 if (access(getenv(DB_ENVIRONMENT), X_OK))
305 return 0;
306 }
307 else {
308 strcpy(path + len, "/objects");
309 if (access(path, X_OK))
310 return 0;
311 }
312
313 strcpy(path + len, "/refs");
314 if (access(path, X_OK))
315 return 0;
316
317 strcpy(path + len, "/HEAD");
318 if (validate_headref(path))
319 return 0;
320
321 return 1;
322}
323
324int is_inside_git_dir(void)
325{
326 if (inside_git_dir < 0)
327 inside_git_dir = is_inside_dir(get_git_dir());
328 return inside_git_dir;
329}
330
331int is_inside_work_tree(void)
332{
333 if (inside_work_tree < 0)
334 inside_work_tree = is_inside_dir(get_git_work_tree());
335 return inside_work_tree;
336}
337
338void setup_work_tree(void)
339{
340 const char *work_tree, *git_dir;
341 static int initialized = 0;
342
343 if (initialized)
344 return;
345 work_tree = get_git_work_tree();
346 git_dir = get_git_dir();
347 if (!is_absolute_path(git_dir))
348 git_dir = real_path(get_git_dir());
349 if (!work_tree || chdir(work_tree))
350 die("This operation must be run in a work tree");
351
352 /*
353 * Make sure subsequent git processes find correct worktree
354 * if $GIT_WORK_TREE is set relative
355 */
356 if (getenv(GIT_WORK_TREE_ENVIRONMENT))
357 setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
358
359 set_git_dir(relative_path(git_dir, work_tree));
360 initialized = 1;
361}
362
363static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
364{
365 char repo_config[PATH_MAX+1];
366
367 /*
368 * git_config() can't be used here because it calls git_pathdup()
369 * to get $GIT_CONFIG/config. That call will make setup_git_env()
370 * set git_dir to ".git".
371 *
372 * We are in gitdir setup, no git dir has been found useable yet.
373 * Use a gentler version of git_config() to check if this repo
374 * is a good one.
375 */
376 snprintf(repo_config, PATH_MAX, "%s/config", gitdir);
377 git_config_early(check_repository_format_version, NULL, repo_config);
378 if (GIT_REPO_VERSION < repository_format_version) {
379 if (!nongit_ok)
380 die ("Expected git repo version <= %d, found %d",
381 GIT_REPO_VERSION, repository_format_version);
382 warning("Expected git repo version <= %d, found %d",
383 GIT_REPO_VERSION, repository_format_version);
384 warning("Please upgrade Git");
385 *nongit_ok = -1;
386 return -1;
387 }
388 return 0;
389}
390
391/*
392 * Try to read the location of the git directory from the .git file,
393 * return path to git directory if found.
394 */
395const char *read_gitfile_gently(const char *path)
396{
397 char *buf;
398 char *dir;
399 const char *slash;
400 struct stat st;
401 int fd;
402 size_t len;
403
404 if (stat(path, &st))
405 return NULL;
406 if (!S_ISREG(st.st_mode))
407 return NULL;
408 fd = open(path, O_RDONLY);
409 if (fd < 0)
410 die_errno("Error opening '%s'", path);
411 buf = xmalloc(st.st_size + 1);
412 len = read_in_full(fd, buf, st.st_size);
413 close(fd);
414 if (len != st.st_size)
415 die("Error reading %s", path);
416 buf[len] = '\0';
417 if (prefixcmp(buf, "gitdir: "))
418 die("Invalid gitfile format: %s", path);
419 while (buf[len - 1] == '\n' || buf[len - 1] == '\r')
420 len--;
421 if (len < 9)
422 die("No path in gitfile: %s", path);
423 buf[len] = '\0';
424 dir = buf + 8;
425
426 if (!is_absolute_path(dir) && (slash = strrchr(path, '/'))) {
427 size_t pathlen = slash+1 - path;
428 size_t dirlen = pathlen + len - 8;
429 dir = xmalloc(dirlen + 1);
430 strncpy(dir, path, pathlen);
431 strncpy(dir + pathlen, buf + 8, len - 8);
432 dir[dirlen] = '\0';
433 free(buf);
434 buf = dir;
435 }
436
437 if (!is_git_directory(dir))
438 die("Not a git repository: %s", dir);
439 path = real_path(dir);
440
441 free(buf);
442 return path;
443}
444
445static const char *setup_explicit_git_dir(const char *gitdirenv,
446 char *cwd, int len,
447 int *nongit_ok)
448{
449 const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
450 const char *worktree;
451 char *gitfile;
452
453 if (PATH_MAX - 40 < strlen(gitdirenv))
454 die("'$%s' too big", GIT_DIR_ENVIRONMENT);
455
456 gitfile = (char*)read_gitfile_gently(gitdirenv);
457 if (gitfile) {
458 gitfile = xstrdup(gitfile);
459 gitdirenv = gitfile;
460 }
461
462 if (!is_git_directory(gitdirenv)) {
463 if (nongit_ok) {
464 *nongit_ok = 1;
465 free(gitfile);
466 return NULL;
467 }
468 die("Not a git repository: '%s'", gitdirenv);
469 }
470
471 if (check_repository_format_gently(gitdirenv, nongit_ok)) {
472 free(gitfile);
473 return NULL;
474 }
475
476 /* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */
477 if (work_tree_env)
478 set_git_work_tree(work_tree_env);
479 else if (is_bare_repository_cfg > 0) {
480 if (git_work_tree_cfg) /* #22.2, #30 */
481 die("core.bare and core.worktree do not make sense");
482
483 /* #18, #26 */
484 set_git_dir(gitdirenv);
485 free(gitfile);
486 return NULL;
487 }
488 else if (git_work_tree_cfg) { /* #6, #14 */
489 if (is_absolute_path(git_work_tree_cfg))
490 set_git_work_tree(git_work_tree_cfg);
491 else {
492 char core_worktree[PATH_MAX];
493 if (chdir(gitdirenv))
494 die_errno("Could not chdir to '%s'", gitdirenv);
495 if (chdir(git_work_tree_cfg))
496 die_errno("Could not chdir to '%s'", git_work_tree_cfg);
497 if (!getcwd(core_worktree, PATH_MAX))
498 die_errno("Could not get directory '%s'", git_work_tree_cfg);
499 if (chdir(cwd))
500 die_errno("Could not come back to cwd");
501 set_git_work_tree(core_worktree);
502 }
503 }
504 else /* #2, #10 */
505 set_git_work_tree(".");
506
507 /* set_git_work_tree() must have been called by now */
508 worktree = get_git_work_tree();
509
510 /* both get_git_work_tree() and cwd are already normalized */
511 if (!strcmp(cwd, worktree)) { /* cwd == worktree */
512 set_git_dir(gitdirenv);
513 free(gitfile);
514 return NULL;
515 }
516
517 if (!prefixcmp(cwd, worktree) &&
518 cwd[strlen(worktree)] == '/') { /* cwd inside worktree */
519 set_git_dir(real_path(gitdirenv));
520 if (chdir(worktree))
521 die_errno("Could not chdir to '%s'", worktree);
522 cwd[len++] = '/';
523 cwd[len] = '\0';
524 free(gitfile);
525 return cwd + strlen(worktree) + 1;
526 }
527
528 /* cwd outside worktree */
529 set_git_dir(gitdirenv);
530 free(gitfile);
531 return NULL;
532}
533
534static const char *setup_discovered_git_dir(const char *gitdir,
535 char *cwd, int offset, int len,
536 int *nongit_ok)
537{
538 if (check_repository_format_gently(gitdir, nongit_ok))
539 return NULL;
540
541 /* --work-tree is set without --git-dir; use discovered one */
542 if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
543 if (offset != len && !is_absolute_path(gitdir))
544 gitdir = xstrdup(real_path(gitdir));
545 if (chdir(cwd))
546 die_errno("Could not come back to cwd");
547 return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok);
548 }
549
550 /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
551 if (is_bare_repository_cfg > 0) {
552 set_git_dir(offset == len ? gitdir : real_path(gitdir));
553 if (chdir(cwd))
554 die_errno("Could not come back to cwd");
555 return NULL;
556 }
557
558 /* #0, #1, #5, #8, #9, #12, #13 */
559 set_git_work_tree(".");
560 if (strcmp(gitdir, DEFAULT_GIT_DIR_ENVIRONMENT))
561 set_git_dir(gitdir);
562 inside_git_dir = 0;
563 inside_work_tree = 1;
564 if (offset == len)
565 return NULL;
566
567 /* Make "offset" point to past the '/', and add a '/' at the end */
568 offset++;
569 cwd[len++] = '/';
570 cwd[len] = 0;
571 return cwd + offset;
572}
573
574/* #16.1, #17.1, #20.1, #21.1, #22.1 (see t1510) */
575static const char *setup_bare_git_dir(char *cwd, int offset, int len, int *nongit_ok)
576{
577 int root_len;
578
579 if (check_repository_format_gently(".", nongit_ok))
580 return NULL;
581
582 /* --work-tree is set without --git-dir; use discovered one */
583 if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
584 const char *gitdir;
585
586 gitdir = offset == len ? "." : xmemdupz(cwd, offset);
587 if (chdir(cwd))
588 die_errno("Could not come back to cwd");
589 return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok);
590 }
591
592 inside_git_dir = 1;
593 inside_work_tree = 0;
594 if (offset != len) {
595 if (chdir(cwd))
596 die_errno("Cannot come back to cwd");
597 root_len = offset_1st_component(cwd);
598 cwd[offset > root_len ? offset : root_len] = '\0';
599 set_git_dir(cwd);
600 }
601 else
602 set_git_dir(".");
603 return NULL;
604}
605
606static const char *setup_nongit(const char *cwd, int *nongit_ok)
607{
608 if (!nongit_ok)
609 die("Not a git repository (or any of the parent directories): %s", DEFAULT_GIT_DIR_ENVIRONMENT);
610 if (chdir(cwd))
611 die_errno("Cannot come back to cwd");
612 *nongit_ok = 1;
613 return NULL;
614}
615
616static dev_t get_device_or_die(const char *path, const char *prefix)
617{
618 struct stat buf;
619 if (stat(path, &buf))
620 die_errno("failed to stat '%s%s%s'",
621 prefix ? prefix : "",
622 prefix ? "/" : "", path);
623 return buf.st_dev;
624}
625
626/*
627 * We cannot decide in this function whether we are in the work tree or
628 * not, since the config can only be read _after_ this function was called.
629 */
630static const char *setup_git_directory_gently_1(int *nongit_ok)
631{
632 const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
633 static char cwd[PATH_MAX+1];
634 const char *gitdirenv, *ret;
635 char *gitfile;
636 int len, offset, ceil_offset;
637 dev_t current_device = 0;
638 int one_filesystem = 1;
639
640 /*
641 * Let's assume that we are in a git repository.
642 * If it turns out later that we are somewhere else, the value will be
643 * updated accordingly.
644 */
645 if (nongit_ok)
646 *nongit_ok = 0;
647
648 if (!getcwd(cwd, sizeof(cwd)-1))
649 die_errno("Unable to read current working directory");
650 offset = len = strlen(cwd);
651
652 /*
653 * If GIT_DIR is set explicitly, we're not going
654 * to do any discovery, but we still do repository
655 * validation.
656 */
657 gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
658 if (gitdirenv)
659 return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
660
661 ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
662 if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
663 ceil_offset = 1;
664
665 /*
666 * Test in the following order (relative to the cwd):
667 * - .git (file containing "gitdir: <path>")
668 * - .git/
669 * - ./ (bare)
670 * - ../.git
671 * - ../.git/
672 * - ../ (bare)
673 * - ../../.git/
674 * etc.
675 */
676 one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
677 if (one_filesystem)
678 current_device = get_device_or_die(".", NULL);
679 for (;;) {
680 gitfile = (char*)read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
681 if (gitfile)
682 gitdirenv = gitfile = xstrdup(gitfile);
683 else {
684 if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
685 gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
686 }
687
688 if (gitdirenv) {
689 ret = setup_discovered_git_dir(gitdirenv,
690 cwd, offset, len,
691 nongit_ok);
692 free(gitfile);
693 return ret;
694 }
695 free(gitfile);
696
697 if (is_git_directory("."))
698 return setup_bare_git_dir(cwd, offset, len, nongit_ok);
699
700 while (--offset > ceil_offset && cwd[offset] != '/');
701 if (offset <= ceil_offset)
702 return setup_nongit(cwd, nongit_ok);
703 if (one_filesystem) {
704 dev_t parent_device = get_device_or_die("..", cwd);
705 if (parent_device != current_device) {
706 if (nongit_ok) {
707 if (chdir(cwd))
708 die_errno("Cannot come back to cwd");
709 *nongit_ok = 1;
710 return NULL;
711 }
712 cwd[offset] = '\0';
713 die("Not a git repository (or any parent up to mount parent %s)\n"
714 "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", cwd);
715 }
716 }
717 if (chdir("..")) {
718 cwd[offset] = '\0';
719 die_errno("Cannot change to '%s/..'", cwd);
720 }
721 }
722}
723
724const char *setup_git_directory_gently(int *nongit_ok)
725{
726 const char *prefix;
727
728 prefix = setup_git_directory_gently_1(nongit_ok);
729 if (startup_info) {
730 startup_info->have_repository = !nongit_ok || !*nongit_ok;
731 startup_info->prefix = prefix;
732 }
733 return prefix;
734}
735
736int git_config_perm(const char *var, const char *value)
737{
738 int i;
739 char *endptr;
740
741 if (value == NULL)
742 return PERM_GROUP;
743
744 if (!strcmp(value, "umask"))
745 return PERM_UMASK;
746 if (!strcmp(value, "group"))
747 return PERM_GROUP;
748 if (!strcmp(value, "all") ||
749 !strcmp(value, "world") ||
750 !strcmp(value, "everybody"))
751 return PERM_EVERYBODY;
752
753 /* Parse octal numbers */
754 i = strtol(value, &endptr, 8);
755
756 /* If not an octal number, maybe true/false? */
757 if (*endptr != 0)
758 return git_config_bool(var, value) ? PERM_GROUP : PERM_UMASK;
759
760 /*
761 * Treat values 0, 1 and 2 as compatibility cases, otherwise it is
762 * a chmod value to restrict to.
763 */
764 switch (i) {
765 case PERM_UMASK: /* 0 */
766 return PERM_UMASK;
767 case OLD_PERM_GROUP: /* 1 */
768 return PERM_GROUP;
769 case OLD_PERM_EVERYBODY: /* 2 */
770 return PERM_EVERYBODY;
771 }
772
773 /* A filemode value was given: 0xxx */
774
775 if ((i & 0600) != 0600)
776 die("Problem with core.sharedRepository filemode value "
777 "(0%.3o).\nThe owner of files must always have "
778 "read and write permissions.", i);
779
780 /*
781 * Mask filemode value. Others can not get write permission.
782 * x flags for directories are handled separately.
783 */
784 return -(i & 0666);
785}
786
787int check_repository_format_version(const char *var, const char *value, void *cb)
788{
789 if (strcmp(var, "core.repositoryformatversion") == 0)
790 repository_format_version = git_config_int(var, value);
791 else if (strcmp(var, "core.sharedrepository") == 0)
792 shared_repository = git_config_perm(var, value);
793 else if (strcmp(var, "core.bare") == 0) {
794 is_bare_repository_cfg = git_config_bool(var, value);
795 if (is_bare_repository_cfg == 1)
796 inside_work_tree = -1;
797 } else if (strcmp(var, "core.worktree") == 0) {
798 if (!value)
799 return config_error_nonbool(var);
800 free(git_work_tree_cfg);
801 git_work_tree_cfg = xstrdup(value);
802 inside_work_tree = -1;
803 }
804 return 0;
805}
806
807int check_repository_format(void)
808{
809 return check_repository_format_gently(get_git_dir(), NULL);
810}
811
812/*
813 * Returns the "prefix", a path to the current working directory
814 * relative to the work tree root, or NULL, if the current working
815 * directory is not a strict subdirectory of the work tree root. The
816 * prefix always ends with a '/' character.
817 */
818const char *setup_git_directory(void)
819{
820 return setup_git_directory_gently(NULL);
821}