Git fork
at reftables-rust 1041 lines 28 kB view raw
1#define USE_THE_REPOSITORY_VARIABLE 2#define DISABLE_SIGN_COMPARE_WARNINGS 3 4#include "git-compat-util.h" 5#include "dir.h" 6#include "environment.h" 7#include "gettext.h" 8#include "hex.h" 9#include "path.h" 10#include "repository.h" 11#include "config.h" 12#include "submodule-config.h" 13#include "submodule.h" 14#include "strbuf.h" 15#include "object-name.h" 16#include "odb.h" 17#include "parse-options.h" 18#include "thread-utils.h" 19#include "tree-walk.h" 20#include "url.h" 21#include "urlmatch.h" 22 23/* 24 * submodule cache lookup structure 25 * There is one shared set of 'struct submodule' entries which can be 26 * looked up by their sha1 blob id of the .gitmodules file and either 27 * using path or name as key. 28 * for_path stores submodule entries with path as key 29 * for_name stores submodule entries with name as key 30 */ 31struct submodule_cache { 32 struct hashmap for_path; 33 struct hashmap for_name; 34 unsigned initialized:1; 35 unsigned gitmodules_read:1; 36}; 37 38/* 39 * thin wrapper struct needed to insert 'struct submodule' entries to 40 * the hashmap 41 */ 42struct submodule_entry { 43 struct hashmap_entry ent; 44 struct submodule *config; 45}; 46 47enum lookup_type { 48 lookup_name, 49 lookup_path 50}; 51 52static int config_path_cmp(const void *cmp_data UNUSED, 53 const struct hashmap_entry *eptr, 54 const struct hashmap_entry *entry_or_key, 55 const void *keydata UNUSED) 56{ 57 const struct submodule_entry *a, *b; 58 59 a = container_of(eptr, const struct submodule_entry, ent); 60 b = container_of(entry_or_key, const struct submodule_entry, ent); 61 62 return strcmp(a->config->path, b->config->path) || 63 !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid); 64} 65 66static int config_name_cmp(const void *cmp_data UNUSED, 67 const struct hashmap_entry *eptr, 68 const struct hashmap_entry *entry_or_key, 69 const void *keydata UNUSED) 70{ 71 const struct submodule_entry *a, *b; 72 73 a = container_of(eptr, const struct submodule_entry, ent); 74 b = container_of(entry_or_key, const struct submodule_entry, ent); 75 76 return strcmp(a->config->name, b->config->name) || 77 !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid); 78} 79 80static struct submodule_cache *submodule_cache_alloc(void) 81{ 82 return xcalloc(1, sizeof(struct submodule_cache)); 83} 84 85static void submodule_cache_init(struct submodule_cache *cache) 86{ 87 hashmap_init(&cache->for_path, config_path_cmp, NULL, 0); 88 hashmap_init(&cache->for_name, config_name_cmp, NULL, 0); 89 cache->initialized = 1; 90} 91 92static void free_one_config(struct submodule_entry *entry) 93{ 94 free((void *) entry->config->path); 95 free((void *) entry->config->name); 96 free((void *) entry->config->branch); 97 free((void *) entry->config->url); 98 free((void *) entry->config->ignore); 99 submodule_update_strategy_release(&entry->config->update_strategy); 100 free(entry->config); 101} 102 103static void submodule_cache_clear(struct submodule_cache *cache) 104{ 105 struct hashmap_iter iter; 106 struct submodule_entry *entry; 107 108 if (!cache->initialized) 109 return; 110 111 /* 112 * We iterate over the name hash here to be symmetric with the 113 * allocation of struct submodule entries. Each is allocated by 114 * their .gitmodules blob sha1 and submodule name. 115 */ 116 hashmap_for_each_entry(&cache->for_name, &iter, entry, 117 ent /* member name */) 118 free_one_config(entry); 119 120 hashmap_clear_and_free(&cache->for_path, struct submodule_entry, ent); 121 hashmap_clear_and_free(&cache->for_name, struct submodule_entry, ent); 122 cache->initialized = 0; 123 cache->gitmodules_read = 0; 124} 125 126void submodule_cache_free(struct submodule_cache *cache) 127{ 128 submodule_cache_clear(cache); 129 free(cache); 130} 131 132static unsigned int hash_oid_string(const struct object_id *oid, 133 const char *string) 134{ 135 return memhash(oid->hash, the_hash_algo->rawsz) + strhash(string); 136} 137 138static void cache_put_path(struct submodule_cache *cache, 139 struct submodule *submodule) 140{ 141 unsigned int hash = hash_oid_string(&submodule->gitmodules_oid, 142 submodule->path); 143 struct submodule_entry *e = xmalloc(sizeof(*e)); 144 hashmap_entry_init(&e->ent, hash); 145 e->config = submodule; 146 hashmap_put(&cache->for_path, &e->ent); 147} 148 149static void cache_remove_path(struct submodule_cache *cache, 150 struct submodule *submodule) 151{ 152 unsigned int hash = hash_oid_string(&submodule->gitmodules_oid, 153 submodule->path); 154 struct submodule_entry e; 155 struct submodule_entry *removed; 156 hashmap_entry_init(&e.ent, hash); 157 e.config = submodule; 158 removed = hashmap_remove_entry(&cache->for_path, &e, ent, NULL); 159 free(removed); 160} 161 162static void cache_add(struct submodule_cache *cache, 163 struct submodule *submodule) 164{ 165 unsigned int hash = hash_oid_string(&submodule->gitmodules_oid, 166 submodule->name); 167 struct submodule_entry *e = xmalloc(sizeof(*e)); 168 hashmap_entry_init(&e->ent, hash); 169 e->config = submodule; 170 hashmap_add(&cache->for_name, &e->ent); 171} 172 173static const struct submodule *cache_lookup_path(struct submodule_cache *cache, 174 const struct object_id *gitmodules_oid, const char *path) 175{ 176 struct submodule_entry *entry; 177 unsigned int hash = hash_oid_string(gitmodules_oid, path); 178 struct submodule_entry key; 179 struct submodule key_config; 180 181 oidcpy(&key_config.gitmodules_oid, gitmodules_oid); 182 key_config.path = path; 183 184 hashmap_entry_init(&key.ent, hash); 185 key.config = &key_config; 186 187 entry = hashmap_get_entry(&cache->for_path, &key, ent, NULL); 188 if (entry) 189 return entry->config; 190 return NULL; 191} 192 193static struct submodule *cache_lookup_name(struct submodule_cache *cache, 194 const struct object_id *gitmodules_oid, const char *name) 195{ 196 struct submodule_entry *entry; 197 unsigned int hash = hash_oid_string(gitmodules_oid, name); 198 struct submodule_entry key; 199 struct submodule key_config; 200 201 oidcpy(&key_config.gitmodules_oid, gitmodules_oid); 202 key_config.name = name; 203 204 hashmap_entry_init(&key.ent, hash); 205 key.config = &key_config; 206 207 entry = hashmap_get_entry(&cache->for_name, &key, ent, NULL); 208 if (entry) 209 return entry->config; 210 return NULL; 211} 212 213int check_submodule_name(const char *name) 214{ 215 /* Disallow empty names */ 216 if (!*name) 217 return -1; 218 219 /* 220 * Look for '..' as a path component. Check is_xplatform_dir_sep() as 221 * separators rather than is_dir_sep(), because we want the name rules 222 * to be consistent across platforms. 223 */ 224 goto in_component; /* always start inside component */ 225 while (*name) { 226 char c = *name++; 227 if (is_xplatform_dir_sep(c)) { 228in_component: 229 if (name[0] == '.' && name[1] == '.' && 230 (!name[2] || is_xplatform_dir_sep(name[2]))) 231 return -1; 232 } 233 } 234 235 return 0; 236} 237 238static int submodule_url_is_relative(const char *url) 239{ 240 return starts_with_dot_slash(url) || starts_with_dot_dot_slash(url); 241} 242 243/* 244 * Count directory components that a relative submodule URL should chop 245 * from the remote_url it is to be resolved against. 246 * 247 * In other words, this counts "../" components at the start of a 248 * submodule URL. 249 * 250 * Returns the number of directory components to chop and writes a 251 * pointer to the next character of url after all leading "./" and 252 * "../" components to out. 253 */ 254static int count_leading_dotdots(const char *url, const char **out) 255{ 256 int result = 0; 257 while (1) { 258 if (starts_with_dot_dot_slash(url)) { 259 result++; 260 url += strlen("../"); 261 continue; 262 } 263 if (starts_with_dot_slash(url)) { 264 url += strlen("./"); 265 continue; 266 } 267 *out = url; 268 return result; 269 } 270} 271/* 272 * Check whether a transport is implemented by git-remote-curl. 273 * 274 * If it is, returns 1 and writes the URL that would be passed to 275 * git-remote-curl to the "out" parameter. 276 * 277 * Otherwise, returns 0 and leaves "out" untouched. 278 * 279 * Examples: 280 * http::https://example.com/repo.git -> 1, https://example.com/repo.git 281 * https://example.com/repo.git -> 1, https://example.com/repo.git 282 * git://example.com/repo.git -> 0 283 * 284 * This is for use in checking for previously exploitable bugs that 285 * required a submodule URL to be passed to git-remote-curl. 286 */ 287static int url_to_curl_url(const char *url, const char **out) 288{ 289 /* 290 * We don't need to check for case-aliases, "http.exe", and so 291 * on because in the default configuration, is_transport_allowed 292 * prevents URLs with those schemes from being cloned 293 * automatically. 294 */ 295 if (skip_prefix(url, "http::", out) || 296 skip_prefix(url, "https::", out) || 297 skip_prefix(url, "ftp::", out) || 298 skip_prefix(url, "ftps::", out)) 299 return 1; 300 if (starts_with(url, "http://") || 301 starts_with(url, "https://") || 302 starts_with(url, "ftp://") || 303 starts_with(url, "ftps://")) { 304 *out = url; 305 return 1; 306 } 307 return 0; 308} 309 310int check_submodule_url(const char *url) 311{ 312 const char *curl_url; 313 314 if (looks_like_command_line_option(url)) 315 return -1; 316 317 if (submodule_url_is_relative(url) || starts_with(url, "git://")) { 318 char *decoded; 319 const char *next; 320 int has_nl; 321 322 /* 323 * This could be appended to an http URL and url-decoded; 324 * check for malicious characters. 325 */ 326 decoded = url_decode(url); 327 has_nl = !!strchr(decoded, '\n'); 328 329 free(decoded); 330 if (has_nl) 331 return -1; 332 333 /* 334 * URLs which escape their root via "../" can overwrite 335 * the host field and previous components, resolving to 336 * URLs like https::example.com/submodule.git and 337 * https:///example.com/submodule.git that were 338 * susceptible to CVE-2020-11008. 339 */ 340 if (count_leading_dotdots(url, &next) > 0 && 341 (*next == ':' || *next == '/')) 342 return -1; 343 } 344 345 else if (url_to_curl_url(url, &curl_url)) { 346 int ret = 0; 347 char *normalized = url_normalize(curl_url, NULL); 348 if (normalized) { 349 char *decoded = url_decode(normalized); 350 if (strchr(decoded, '\n')) 351 ret = -1; 352 free(normalized); 353 free(decoded); 354 } else { 355 ret = -1; 356 } 357 358 return ret; 359 } 360 361 return 0; 362} 363 364static int name_and_item_from_var(const char *var, struct strbuf *name, 365 struct strbuf *item) 366{ 367 const char *subsection, *key; 368 size_t subsection_len; 369 int parse; 370 parse = parse_config_key(var, "submodule", &subsection, 371 &subsection_len, &key); 372 if (parse < 0 || !subsection) 373 return 0; 374 375 strbuf_add(name, subsection, subsection_len); 376 if (check_submodule_name(name->buf) < 0) { 377 warning(_("ignoring suspicious submodule name: %s"), name->buf); 378 strbuf_release(name); 379 return 0; 380 } 381 382 strbuf_addstr(item, key); 383 384 return 1; 385} 386 387static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache, 388 const struct object_id *gitmodules_oid, const char *name) 389{ 390 struct submodule *submodule; 391 struct strbuf name_buf = STRBUF_INIT; 392 393 submodule = cache_lookup_name(cache, gitmodules_oid, name); 394 if (submodule) 395 return submodule; 396 397 submodule = xmalloc(sizeof(*submodule)); 398 399 strbuf_addstr(&name_buf, name); 400 submodule->name = strbuf_detach(&name_buf, NULL); 401 402 submodule->path = NULL; 403 submodule->url = NULL; 404 submodule->update_strategy.type = SM_UPDATE_UNSPECIFIED; 405 submodule->update_strategy.command = NULL; 406 submodule->fetch_recurse = RECURSE_SUBMODULES_NONE; 407 submodule->ignore = NULL; 408 submodule->branch = NULL; 409 submodule->recommend_shallow = -1; 410 411 oidcpy(&submodule->gitmodules_oid, gitmodules_oid); 412 413 cache_add(cache, submodule); 414 415 return submodule; 416} 417 418static int parse_fetch_recurse(const char *opt, const char *arg, 419 int die_on_error) 420{ 421 switch (git_parse_maybe_bool(arg)) { 422 case 1: 423 return RECURSE_SUBMODULES_ON; 424 case 0: 425 return RECURSE_SUBMODULES_OFF; 426 default: 427 if (!strcmp(arg, "on-demand")) 428 return RECURSE_SUBMODULES_ON_DEMAND; 429 /* 430 * Please update $__git_fetch_recurse_submodules in 431 * git-completion.bash when you add new options. 432 */ 433 if (die_on_error) 434 die("bad %s argument: %s", opt, arg); 435 else 436 return RECURSE_SUBMODULES_ERROR; 437 } 438} 439 440int parse_submodule_fetchjobs(const char *var, const char *value, 441 const struct key_value_info *kvi) 442{ 443 int fetchjobs = git_config_int(var, value, kvi); 444 if (fetchjobs < 0) 445 die(_("negative values not allowed for submodule.fetchJobs")); 446 if (!fetchjobs) 447 fetchjobs = online_cpus(); 448 return fetchjobs; 449} 450 451int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg) 452{ 453 return parse_fetch_recurse(opt, arg, 1); 454} 455 456int option_fetch_parse_recurse_submodules(const struct option *opt, 457 const char *arg, int unset) 458{ 459 int *v; 460 461 if (!opt->value) 462 return -1; 463 464 v = opt->value; 465 466 if (unset) { 467 *v = RECURSE_SUBMODULES_OFF; 468 } else { 469 if (arg) 470 *v = parse_fetch_recurse_submodules_arg(opt->long_name, arg); 471 else 472 *v = RECURSE_SUBMODULES_ON; 473 } 474 return 0; 475} 476 477static int parse_update_recurse(const char *opt, const char *arg, 478 int die_on_error) 479{ 480 switch (git_parse_maybe_bool(arg)) { 481 case 1: 482 return RECURSE_SUBMODULES_ON; 483 case 0: 484 return RECURSE_SUBMODULES_OFF; 485 default: 486 if (die_on_error) 487 die("bad %s argument: %s", opt, arg); 488 return RECURSE_SUBMODULES_ERROR; 489 } 490} 491 492int parse_update_recurse_submodules_arg(const char *opt, const char *arg) 493{ 494 return parse_update_recurse(opt, arg, 1); 495} 496 497static int parse_push_recurse(const char *opt, const char *arg, 498 int die_on_error) 499{ 500 switch (git_parse_maybe_bool(arg)) { 501 case 1: 502 /* There's no simple "on" value when pushing */ 503 if (die_on_error) 504 die("bad %s argument: %s", opt, arg); 505 else 506 return RECURSE_SUBMODULES_ERROR; 507 case 0: 508 return RECURSE_SUBMODULES_OFF; 509 default: 510 if (!strcmp(arg, "on-demand")) 511 return RECURSE_SUBMODULES_ON_DEMAND; 512 else if (!strcmp(arg, "check")) 513 return RECURSE_SUBMODULES_CHECK; 514 else if (!strcmp(arg, "only")) 515 return RECURSE_SUBMODULES_ONLY; 516 /* 517 * Please update $__git_push_recurse_submodules in 518 * git-completion.bash when you add new modes. 519 */ 520 else if (die_on_error) 521 die("bad %s argument: %s", opt, arg); 522 else 523 return RECURSE_SUBMODULES_ERROR; 524 } 525} 526 527int parse_push_recurse_submodules_arg(const char *opt, const char *arg) 528{ 529 return parse_push_recurse(opt, arg, 1); 530} 531 532static void warn_multiple_config(const struct object_id *treeish_name, 533 const char *name, const char *option) 534{ 535 const char *commit_string = "WORKTREE"; 536 if (treeish_name) 537 commit_string = oid_to_hex(treeish_name); 538 warning("%s:.gitmodules, multiple configurations found for " 539 "'submodule.%s.%s'. Skipping second one!", 540 commit_string, name, option); 541} 542 543static void warn_command_line_option(const char *var, const char *value) 544{ 545 warning(_("ignoring '%s' which may be interpreted as" 546 " a command-line option: %s"), var, value); 547} 548 549struct parse_config_parameter { 550 struct submodule_cache *cache; 551 const struct object_id *treeish_name; 552 const struct object_id *gitmodules_oid; 553 int overwrite; 554}; 555 556/* 557 * Parse a config item from .gitmodules. 558 * 559 * This does not handle submodule-related configuration from the main 560 * config store (.git/config, etc). Callers are responsible for 561 * checking for overrides in the main config store when appropriate. 562 */ 563static int parse_config(const char *var, const char *value, 564 const struct config_context *ctx UNUSED, void *data) 565{ 566 struct parse_config_parameter *me = data; 567 struct submodule *submodule; 568 struct strbuf name = STRBUF_INIT, item = STRBUF_INIT; 569 int ret = 0; 570 571 /* this also ensures that we only parse submodule entries */ 572 if (!name_and_item_from_var(var, &name, &item)) 573 return 0; 574 575 submodule = lookup_or_create_by_name(me->cache, 576 me->gitmodules_oid, 577 name.buf); 578 579 if (!strcmp(item.buf, "path")) { 580 if (!value) 581 ret = config_error_nonbool(var); 582 else if (looks_like_command_line_option(value)) 583 warn_command_line_option(var, value); 584 else if (!me->overwrite && submodule->path) 585 warn_multiple_config(me->treeish_name, submodule->name, 586 "path"); 587 else { 588 if (submodule->path) 589 cache_remove_path(me->cache, submodule); 590 free((void *) submodule->path); 591 submodule->path = xstrdup(value); 592 cache_put_path(me->cache, submodule); 593 } 594 } else if (!strcmp(item.buf, "fetchrecursesubmodules")) { 595 /* when parsing worktree configurations we can die early */ 596 int die_on_error = is_null_oid(me->gitmodules_oid); 597 if (!me->overwrite && 598 submodule->fetch_recurse != RECURSE_SUBMODULES_NONE) 599 warn_multiple_config(me->treeish_name, submodule->name, 600 "fetchrecursesubmodules"); 601 else 602 submodule->fetch_recurse = parse_fetch_recurse( 603 var, value, 604 die_on_error); 605 } else if (!strcmp(item.buf, "ignore")) { 606 if (!value) 607 ret = config_error_nonbool(var); 608 else if (!me->overwrite && submodule->ignore) 609 warn_multiple_config(me->treeish_name, submodule->name, 610 "ignore"); 611 else if (strcmp(value, "untracked") && 612 strcmp(value, "dirty") && 613 strcmp(value, "all") && 614 strcmp(value, "none")) 615 warning("Invalid parameter '%s' for config option " 616 "'submodule.%s.ignore'", value, name.buf); 617 else { 618 free((void *) submodule->ignore); 619 submodule->ignore = xstrdup(value); 620 } 621 } else if (!strcmp(item.buf, "url")) { 622 if (!value) { 623 ret = config_error_nonbool(var); 624 } else if (looks_like_command_line_option(value)) { 625 warn_command_line_option(var, value); 626 } else if (!me->overwrite && submodule->url) { 627 warn_multiple_config(me->treeish_name, submodule->name, 628 "url"); 629 } else { 630 free((void *) submodule->url); 631 submodule->url = xstrdup(value); 632 } 633 } else if (!strcmp(item.buf, "update")) { 634 if (!value) 635 ret = config_error_nonbool(var); 636 else if (!me->overwrite && 637 submodule->update_strategy.type != SM_UPDATE_UNSPECIFIED) 638 warn_multiple_config(me->treeish_name, submodule->name, 639 "update"); 640 else if (parse_submodule_update_strategy(value, 641 &submodule->update_strategy) < 0 || 642 submodule->update_strategy.type == SM_UPDATE_COMMAND) 643 die(_("invalid value for '%s'"), var); 644 } else if (!strcmp(item.buf, "shallow")) { 645 if (!me->overwrite && submodule->recommend_shallow != -1) 646 warn_multiple_config(me->treeish_name, submodule->name, 647 "shallow"); 648 else 649 submodule->recommend_shallow = 650 git_config_bool(var, value); 651 } else if (!strcmp(item.buf, "branch")) { 652 if (!value) 653 ret = config_error_nonbool(var); 654 else if (!me->overwrite && submodule->branch) 655 warn_multiple_config(me->treeish_name, submodule->name, 656 "branch"); 657 else { 658 free((void *)submodule->branch); 659 submodule->branch = xstrdup(value); 660 } 661 } 662 663 strbuf_release(&name); 664 strbuf_release(&item); 665 666 return ret; 667} 668 669static int gitmodule_oid_from_commit(const struct object_id *treeish_name, 670 struct object_id *gitmodules_oid, 671 struct strbuf *rev) 672{ 673 int ret = 0; 674 675 if (is_null_oid(treeish_name)) { 676 oidclr(gitmodules_oid, the_repository->hash_algo); 677 return 1; 678 } 679 680 strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name)); 681 if (repo_get_oid(the_repository, rev->buf, gitmodules_oid) >= 0) 682 ret = 1; 683 684 return ret; 685} 686 687/* This does a lookup of a submodule configuration by name or by path 688 * (key) with on-demand reading of the appropriate .gitmodules from 689 * revisions. 690 */ 691static const struct submodule *config_from(struct submodule_cache *cache, 692 const struct object_id *treeish_name, const char *key, 693 enum lookup_type lookup_type) 694{ 695 struct strbuf rev = STRBUF_INIT; 696 unsigned long config_size; 697 char *config = NULL; 698 struct object_id oid; 699 enum object_type type; 700 const struct submodule *submodule = NULL; 701 struct parse_config_parameter parameter; 702 703 /* 704 * If any parameter except the cache is a NULL pointer just 705 * return the first submodule. Can be used to check whether 706 * there are any submodules parsed. 707 */ 708 if (!treeish_name || !key) { 709 struct hashmap_iter iter; 710 struct submodule_entry *entry; 711 712 entry = hashmap_iter_first_entry(&cache->for_name, &iter, 713 struct submodule_entry, 714 ent /* member name */); 715 if (!entry) 716 return NULL; 717 return entry->config; 718 } 719 720 if (!gitmodule_oid_from_commit(treeish_name, &oid, &rev)) 721 goto out; 722 723 switch (lookup_type) { 724 case lookup_name: 725 submodule = cache_lookup_name(cache, &oid, key); 726 break; 727 case lookup_path: 728 submodule = cache_lookup_path(cache, &oid, key); 729 break; 730 } 731 if (submodule) 732 goto out; 733 734 config = odb_read_object(the_repository->objects, &oid, 735 &type, &config_size); 736 if (!config || type != OBJ_BLOB) 737 goto out; 738 739 /* fill the submodule config into the cache */ 740 parameter.cache = cache; 741 parameter.treeish_name = treeish_name; 742 parameter.gitmodules_oid = &oid; 743 parameter.overwrite = 0; 744 git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf, 745 config, config_size, &parameter, CONFIG_SCOPE_UNKNOWN, NULL); 746 strbuf_release(&rev); 747 free(config); 748 749 switch (lookup_type) { 750 case lookup_name: 751 return cache_lookup_name(cache, &oid, key); 752 case lookup_path: 753 return cache_lookup_path(cache, &oid, key); 754 default: 755 return NULL; 756 } 757 758out: 759 strbuf_release(&rev); 760 free(config); 761 return submodule; 762} 763 764static void submodule_cache_check_init(struct repository *repo) 765{ 766 if (repo->submodule_cache && repo->submodule_cache->initialized) 767 return; 768 769 if (!repo->submodule_cache) 770 repo->submodule_cache = submodule_cache_alloc(); 771 772 submodule_cache_init(repo->submodule_cache); 773} 774 775/* 776 * Note: This function is private for a reason, the '.gitmodules' file should 777 * not be used as a mechanism to retrieve arbitrary configuration stored in 778 * the repository. 779 * 780 * Runs the provided config function on the '.gitmodules' file found in the 781 * working directory. 782 */ 783static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data) 784{ 785 if (repo->worktree) { 786 struct git_config_source config_source = { 787 0, .scope = CONFIG_SCOPE_SUBMODULE 788 }; 789 const struct config_options opts = { 0 }; 790 struct object_id oid; 791 char *file; 792 char *oidstr = NULL; 793 794 file = repo_worktree_path(repo, GITMODULES_FILE); 795 if (file_exists(file)) { 796 config_source.file = file; 797 } else if (repo_get_oid(repo, GITMODULES_INDEX, &oid) >= 0 || 798 repo_get_oid(repo, GITMODULES_HEAD, &oid) >= 0) { 799 config_source.blob = oidstr = xstrdup(oid_to_hex(&oid)); 800 if (repo != the_repository) 801 odb_add_submodule_source_by_path(the_repository->objects, 802 repo->objects->sources->path); 803 } else { 804 goto out; 805 } 806 807 config_with_options(fn, data, &config_source, repo, &opts); 808 809out: 810 free(oidstr); 811 free(file); 812 } 813} 814 815static int gitmodules_cb(const char *var, const char *value, 816 const struct config_context *ctx, void *data) 817{ 818 struct repository *repo = data; 819 struct parse_config_parameter parameter; 820 821 parameter.cache = repo->submodule_cache; 822 parameter.treeish_name = NULL; 823 parameter.gitmodules_oid = null_oid(the_hash_algo); 824 parameter.overwrite = 1; 825 826 return parse_config(var, value, ctx, &parameter); 827} 828 829void repo_read_gitmodules(struct repository *repo, int skip_if_read) 830{ 831 submodule_cache_check_init(repo); 832 833 if (repo->submodule_cache->gitmodules_read && skip_if_read) 834 return; 835 836 if (repo_read_index(repo) < 0) 837 return; 838 839 if (!is_gitmodules_unmerged(repo->index)) 840 config_from_gitmodules(gitmodules_cb, repo, repo); 841 842 repo->submodule_cache->gitmodules_read = 1; 843} 844 845void gitmodules_config_oid(const struct object_id *commit_oid) 846{ 847 struct strbuf rev = STRBUF_INIT; 848 struct object_id oid; 849 850 submodule_cache_check_init(the_repository); 851 852 if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) { 853 git_config_from_blob_oid(gitmodules_cb, rev.buf, 854 the_repository, &oid, the_repository, 855 CONFIG_SCOPE_UNKNOWN); 856 } 857 strbuf_release(&rev); 858 859 the_repository->submodule_cache->gitmodules_read = 1; 860} 861 862const struct submodule *submodule_from_name(struct repository *r, 863 const struct object_id *treeish_name, 864 const char *name) 865{ 866 repo_read_gitmodules(r, 1); 867 return config_from(r->submodule_cache, treeish_name, name, lookup_name); 868} 869 870const struct submodule *submodule_from_path(struct repository *r, 871 const struct object_id *treeish_name, 872 const char *path) 873{ 874 repo_read_gitmodules(r, 1); 875 return config_from(r->submodule_cache, treeish_name, path, lookup_path); 876} 877 878/** 879 * Used internally by submodules_of_tree(). Recurses into 'treeish_name' 880 * and appends submodule entries to 'out'. The submodule_cache expects 881 * a root-level treeish_name and paths, so keep track of these values 882 * with 'root_tree' and 'prefix'. 883 */ 884static void traverse_tree_submodules(struct repository *r, 885 const struct object_id *root_tree, 886 char *prefix, 887 const struct object_id *treeish_name, 888 struct submodule_entry_list *out) 889{ 890 struct tree_desc tree; 891 struct submodule_tree_entry *st_entry; 892 struct name_entry name_entry; 893 char *tree_path = NULL; 894 char *tree_buf; 895 896 tree_buf = fill_tree_descriptor(r, &tree, treeish_name); 897 while (tree_entry(&tree, &name_entry)) { 898 if (prefix) 899 tree_path = 900 mkpathdup("%s/%s", prefix, name_entry.path); 901 else 902 tree_path = xstrdup(name_entry.path); 903 904 if (S_ISGITLINK(name_entry.mode) && 905 is_tree_submodule_active(r, root_tree, tree_path)) { 906 ALLOC_GROW(out->entries, out->entry_nr + 1, 907 out->entry_alloc); 908 st_entry = &out->entries[out->entry_nr++]; 909 910 st_entry->name_entry = xmalloc(sizeof(*st_entry->name_entry)); 911 *st_entry->name_entry = name_entry; 912 st_entry->submodule = 913 submodule_from_path(r, root_tree, tree_path); 914 st_entry->repo = xmalloc(sizeof(*st_entry->repo)); 915 if (repo_submodule_init(st_entry->repo, r, tree_path, 916 root_tree)) 917 FREE_AND_NULL(st_entry->repo); 918 919 } else if (S_ISDIR(name_entry.mode)) 920 traverse_tree_submodules(r, root_tree, tree_path, 921 &name_entry.oid, out); 922 free(tree_path); 923 } 924 925 free(tree_buf); 926} 927 928void submodules_of_tree(struct repository *r, 929 const struct object_id *treeish_name, 930 struct submodule_entry_list *out) 931{ 932 CALLOC_ARRAY(out->entries, 0); 933 out->entry_nr = 0; 934 out->entry_alloc = 0; 935 936 traverse_tree_submodules(r, treeish_name, NULL, treeish_name, out); 937} 938 939void submodule_entry_list_release(struct submodule_entry_list *list) 940{ 941 for (size_t i = 0; i < list->entry_nr; i++) { 942 free(list->entries[i].name_entry); 943 repo_clear(list->entries[i].repo); 944 free(list->entries[i].repo); 945 } 946 free(list->entries); 947} 948 949void submodule_free(struct repository *r) 950{ 951 if (r->submodule_cache) 952 submodule_cache_clear(r->submodule_cache); 953} 954 955static int config_print_callback(const char *var, const char *value, 956 const struct config_context *ctx UNUSED, 957 void *cb_data) 958{ 959 char *wanted_key = cb_data; 960 961 if (!strcmp(wanted_key, var)) 962 printf("%s\n", value); 963 964 return 0; 965} 966 967int print_config_from_gitmodules(struct repository *repo, const char *key) 968{ 969 int ret; 970 char *store_key; 971 972 ret = git_config_parse_key(key, &store_key, NULL); 973 if (ret < 0) 974 return CONFIG_INVALID_KEY; 975 976 config_from_gitmodules(config_print_callback, repo, store_key); 977 978 free(store_key); 979 return 0; 980} 981 982int config_set_in_gitmodules_file_gently(const char *key, const char *value) 983{ 984 int ret; 985 986 ret = repo_config_set_in_file_gently(the_repository, GITMODULES_FILE, key, NULL, value); 987 if (ret < 0) 988 /* Maybe the user already did that, don't error out here */ 989 warning(_("Could not update .gitmodules entry %s"), key); 990 991 return ret; 992} 993 994struct fetch_config { 995 int *max_children; 996 int *recurse_submodules; 997}; 998 999static int gitmodules_fetch_config(const char *var, const char *value, 1000 const struct config_context *ctx, 1001 void *cb) 1002{ 1003 struct fetch_config *config = cb; 1004 if (!strcmp(var, "submodule.fetchjobs")) { 1005 if (config->max_children) 1006 *(config->max_children) = 1007 parse_submodule_fetchjobs(var, value, ctx->kvi); 1008 return 0; 1009 } else if (!strcmp(var, "fetch.recursesubmodules")) { 1010 if (config->recurse_submodules) 1011 *(config->recurse_submodules) = 1012 parse_fetch_recurse_submodules_arg(var, value); 1013 return 0; 1014 } 1015 1016 return 0; 1017} 1018 1019void fetch_config_from_gitmodules(int *max_children, int *recurse_submodules) 1020{ 1021 struct fetch_config config = { 1022 .max_children = max_children, 1023 .recurse_submodules = recurse_submodules 1024 }; 1025 config_from_gitmodules(gitmodules_fetch_config, the_repository, &config); 1026} 1027 1028static int gitmodules_update_clone_config(const char *var, const char *value, 1029 const struct config_context *ctx, 1030 void *cb) 1031{ 1032 int *max_jobs = cb; 1033 if (!strcmp(var, "submodule.fetchjobs")) 1034 *max_jobs = parse_submodule_fetchjobs(var, value, ctx->kvi); 1035 return 0; 1036} 1037 1038void update_clone_config_from_gitmodules(int *max_jobs) 1039{ 1040 config_from_gitmodules(gitmodules_update_clone_config, the_repository, &max_jobs); 1041}