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