git

Форк
0
/
submodule-config.c 
1038 строк · 27.2 Кб
1
#define USE_THE_REPOSITORY_VARIABLE
2

3
#include "git-compat-util.h"
4
#include "dir.h"
5
#include "environment.h"
6
#include "gettext.h"
7
#include "hex.h"
8
#include "path.h"
9
#include "repository.h"
10
#include "config.h"
11
#include "submodule-config.h"
12
#include "submodule.h"
13
#include "strbuf.h"
14
#include "object-name.h"
15
#include "object-store-ll.h"
16
#include "parse-options.h"
17
#include "thread-utils.h"
18
#include "tree-walk.h"
19
#include "url.h"
20
#include "urlmatch.h"
21

22
/*
23
 * submodule cache lookup structure
24
 * There is one shared set of 'struct submodule' entries which can be
25
 * looked up by their sha1 blob id of the .gitmodules file and either
26
 * using path or name as key.
27
 * for_path stores submodule entries with path as key
28
 * for_name stores submodule entries with name as key
29
 */
30
struct submodule_cache {
31
	struct hashmap for_path;
32
	struct hashmap for_name;
33
	unsigned initialized:1;
34
	unsigned gitmodules_read:1;
35
};
36

37
/*
38
 * thin wrapper struct needed to insert 'struct submodule' entries to
39
 * the hashmap
40
 */
41
struct submodule_entry {
42
	struct hashmap_entry ent;
43
	struct submodule *config;
44
};
45

46
enum lookup_type {
47
	lookup_name,
48
	lookup_path
49
};
50

51
static int config_path_cmp(const void *cmp_data UNUSED,
52
			   const struct hashmap_entry *eptr,
53
			   const struct hashmap_entry *entry_or_key,
54
			   const void *keydata UNUSED)
55
{
56
	const struct submodule_entry *a, *b;
57

58
	a = container_of(eptr, const struct submodule_entry, ent);
59
	b = container_of(entry_or_key, const struct submodule_entry, ent);
60

61
	return strcmp(a->config->path, b->config->path) ||
62
	       !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
63
}
64

65
static int config_name_cmp(const void *cmp_data UNUSED,
66
			   const struct hashmap_entry *eptr,
67
			   const struct hashmap_entry *entry_or_key,
68
			   const void *keydata UNUSED)
69
{
70
	const struct submodule_entry *a, *b;
71

72
	a = container_of(eptr, const struct submodule_entry, ent);
73
	b = container_of(entry_or_key, const struct submodule_entry, ent);
74

75
	return strcmp(a->config->name, b->config->name) ||
76
	       !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
77
}
78

79
static struct submodule_cache *submodule_cache_alloc(void)
80
{
81
	return xcalloc(1, sizeof(struct submodule_cache));
82
}
83

84
static void submodule_cache_init(struct submodule_cache *cache)
85
{
86
	hashmap_init(&cache->for_path, config_path_cmp, NULL, 0);
87
	hashmap_init(&cache->for_name, config_name_cmp, NULL, 0);
88
	cache->initialized = 1;
89
}
90

91
static void free_one_config(struct submodule_entry *entry)
92
{
93
	free((void *) entry->config->path);
94
	free((void *) entry->config->name);
95
	free((void *) entry->config->branch);
96
	free((void *) entry->config->url);
97
	free((void *) entry->config->ignore);
98
	free((void *) entry->config->update_strategy.command);
99
	free(entry->config);
100
}
101

102
static void submodule_cache_clear(struct submodule_cache *cache)
103
{
104
	struct hashmap_iter iter;
105
	struct submodule_entry *entry;
106

107
	if (!cache->initialized)
108
		return;
109

110
	/*
111
	 * We iterate over the name hash here to be symmetric with the
112
	 * allocation of struct submodule entries. Each is allocated by
113
	 * their .gitmodules blob sha1 and submodule name.
114
	 */
115
	hashmap_for_each_entry(&cache->for_name, &iter, entry,
116
				ent /* member name */)
117
		free_one_config(entry);
118

119
	hashmap_clear_and_free(&cache->for_path, struct submodule_entry, ent);
120
	hashmap_clear_and_free(&cache->for_name, struct submodule_entry, ent);
121
	cache->initialized = 0;
122
	cache->gitmodules_read = 0;
123
}
124

125
void submodule_cache_free(struct submodule_cache *cache)
126
{
127
	submodule_cache_clear(cache);
128
	free(cache);
129
}
130

131
static unsigned int hash_oid_string(const struct object_id *oid,
132
				    const char *string)
133
{
134
	return memhash(oid->hash, the_hash_algo->rawsz) + strhash(string);
135
}
136

137
static void cache_put_path(struct submodule_cache *cache,
138
			   struct submodule *submodule)
139
{
140
	unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
141
					    submodule->path);
142
	struct submodule_entry *e = xmalloc(sizeof(*e));
143
	hashmap_entry_init(&e->ent, hash);
144
	e->config = submodule;
145
	hashmap_put(&cache->for_path, &e->ent);
146
}
147

148
static void cache_remove_path(struct submodule_cache *cache,
149
			      struct submodule *submodule)
150
{
151
	unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
152
					    submodule->path);
153
	struct submodule_entry e;
154
	struct submodule_entry *removed;
155
	hashmap_entry_init(&e.ent, hash);
156
	e.config = submodule;
157
	removed = hashmap_remove_entry(&cache->for_path, &e, ent, NULL);
158
	free(removed);
159
}
160

161
static void cache_add(struct submodule_cache *cache,
162
		      struct submodule *submodule)
163
{
164
	unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
165
					    submodule->name);
166
	struct submodule_entry *e = xmalloc(sizeof(*e));
167
	hashmap_entry_init(&e->ent, hash);
168
	e->config = submodule;
169
	hashmap_add(&cache->for_name, &e->ent);
170
}
171

172
static const struct submodule *cache_lookup_path(struct submodule_cache *cache,
173
		const struct object_id *gitmodules_oid, const char *path)
174
{
175
	struct submodule_entry *entry;
176
	unsigned int hash = hash_oid_string(gitmodules_oid, path);
177
	struct submodule_entry key;
178
	struct submodule key_config;
179

180
	oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
181
	key_config.path = path;
182

183
	hashmap_entry_init(&key.ent, hash);
184
	key.config = &key_config;
185

186
	entry = hashmap_get_entry(&cache->for_path, &key, ent, NULL);
187
	if (entry)
188
		return entry->config;
189
	return NULL;
190
}
191

192
static struct submodule *cache_lookup_name(struct submodule_cache *cache,
193
		const struct object_id *gitmodules_oid, const char *name)
194
{
195
	struct submodule_entry *entry;
196
	unsigned int hash = hash_oid_string(gitmodules_oid, name);
197
	struct submodule_entry key;
198
	struct submodule key_config;
199

200
	oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
201
	key_config.name = name;
202

203
	hashmap_entry_init(&key.ent, hash);
204
	key.config = &key_config;
205

206
	entry = hashmap_get_entry(&cache->for_name, &key, ent, NULL);
207
	if (entry)
208
		return entry->config;
209
	return NULL;
210
}
211

212
int check_submodule_name(const char *name)
213
{
214
	/* Disallow empty names */
215
	if (!*name)
216
		return -1;
217

218
	/*
219
	 * Look for '..' as a path component. Check is_xplatform_dir_sep() as
220
	 * separators rather than is_dir_sep(), because we want the name rules
221
	 * to be consistent across platforms.
222
	 */
223
	goto in_component; /* always start inside component */
224
	while (*name) {
225
		char c = *name++;
226
		if (is_xplatform_dir_sep(c)) {
227
in_component:
228
			if (name[0] == '.' && name[1] == '.' &&
229
			    (!name[2] || is_xplatform_dir_sep(name[2])))
230
				return -1;
231
		}
232
	}
233

234
	return 0;
235
}
236

237
static int starts_with_dot_slash(const char *const path)
238
{
239
	return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
240
				PATH_MATCH_XPLATFORM);
241
}
242

243
static int starts_with_dot_dot_slash(const char *const path)
244
{
245
	return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
246
				PATH_MATCH_XPLATFORM);
247
}
248

249
static int submodule_url_is_relative(const char *url)
250
{
251
	return starts_with_dot_slash(url) || starts_with_dot_dot_slash(url);
252
}
253

254
/*
255
 * Count directory components that a relative submodule URL should chop
256
 * from the remote_url it is to be resolved against.
257
 *
258
 * In other words, this counts "../" components at the start of a
259
 * submodule URL.
260
 *
261
 * Returns the number of directory components to chop and writes a
262
 * pointer to the next character of url after all leading "./" and
263
 * "../" components to out.
264
 */
265
static int count_leading_dotdots(const char *url, const char **out)
266
{
267
	int result = 0;
268
	while (1) {
269
		if (starts_with_dot_dot_slash(url)) {
270
			result++;
271
			url += strlen("../");
272
			continue;
273
		}
274
		if (starts_with_dot_slash(url)) {
275
			url += strlen("./");
276
			continue;
277
		}
278
		*out = url;
279
		return result;
280
	}
281
}
282
/*
283
 * Check whether a transport is implemented by git-remote-curl.
284
 *
285
 * If it is, returns 1 and writes the URL that would be passed to
286
 * git-remote-curl to the "out" parameter.
287
 *
288
 * Otherwise, returns 0 and leaves "out" untouched.
289
 *
290
 * Examples:
291
 *   http::https://example.com/repo.git -> 1, https://example.com/repo.git
292
 *   https://example.com/repo.git -> 1, https://example.com/repo.git
293
 *   git://example.com/repo.git -> 0
294
 *
295
 * This is for use in checking for previously exploitable bugs that
296
 * required a submodule URL to be passed to git-remote-curl.
297
 */
298
static int url_to_curl_url(const char *url, const char **out)
299
{
300
	/*
301
	 * We don't need to check for case-aliases, "http.exe", and so
302
	 * on because in the default configuration, is_transport_allowed
303
	 * prevents URLs with those schemes from being cloned
304
	 * automatically.
305
	 */
306
	if (skip_prefix(url, "http::", out) ||
307
	    skip_prefix(url, "https::", out) ||
308
	    skip_prefix(url, "ftp::", out) ||
309
	    skip_prefix(url, "ftps::", out))
310
		return 1;
311
	if (starts_with(url, "http://") ||
312
	    starts_with(url, "https://") ||
313
	    starts_with(url, "ftp://") ||
314
	    starts_with(url, "ftps://")) {
315
		*out = url;
316
		return 1;
317
	}
318
	return 0;
319
}
320

321
int check_submodule_url(const char *url)
322
{
323
	const char *curl_url;
324

325
	if (looks_like_command_line_option(url))
326
		return -1;
327

328
	if (submodule_url_is_relative(url) || starts_with(url, "git://")) {
329
		char *decoded;
330
		const char *next;
331
		int has_nl;
332

333
		/*
334
		 * This could be appended to an http URL and url-decoded;
335
		 * check for malicious characters.
336
		 */
337
		decoded = url_decode(url);
338
		has_nl = !!strchr(decoded, '\n');
339

340
		free(decoded);
341
		if (has_nl)
342
			return -1;
343

344
		/*
345
		 * URLs which escape their root via "../" can overwrite
346
		 * the host field and previous components, resolving to
347
		 * URLs like https::example.com/submodule.git and
348
		 * https:///example.com/submodule.git that were
349
		 * susceptible to CVE-2020-11008.
350
		 */
351
		if (count_leading_dotdots(url, &next) > 0 &&
352
		    (*next == ':' || *next == '/'))
353
			return -1;
354
	}
355

356
	else if (url_to_curl_url(url, &curl_url)) {
357
		int ret = 0;
358
		char *normalized = url_normalize(curl_url, NULL);
359
		if (normalized) {
360
			char *decoded = url_decode(normalized);
361
			if (strchr(decoded, '\n'))
362
				ret = -1;
363
			free(normalized);
364
			free(decoded);
365
		} else {
366
			ret = -1;
367
		}
368

369
		return ret;
370
	}
371

372
	return 0;
373
}
374

375
static int name_and_item_from_var(const char *var, struct strbuf *name,
376
				  struct strbuf *item)
377
{
378
	const char *subsection, *key;
379
	size_t subsection_len;
380
	int parse;
381
	parse = parse_config_key(var, "submodule", &subsection,
382
			&subsection_len, &key);
383
	if (parse < 0 || !subsection)
384
		return 0;
385

386
	strbuf_add(name, subsection, subsection_len);
387
	if (check_submodule_name(name->buf) < 0) {
388
		warning(_("ignoring suspicious submodule name: %s"), name->buf);
389
		strbuf_release(name);
390
		return 0;
391
	}
392

393
	strbuf_addstr(item, key);
394

395
	return 1;
396
}
397

398
static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache,
399
		const struct object_id *gitmodules_oid, const char *name)
400
{
401
	struct submodule *submodule;
402
	struct strbuf name_buf = STRBUF_INIT;
403

404
	submodule = cache_lookup_name(cache, gitmodules_oid, name);
405
	if (submodule)
406
		return submodule;
407

408
	submodule = xmalloc(sizeof(*submodule));
409

410
	strbuf_addstr(&name_buf, name);
411
	submodule->name = strbuf_detach(&name_buf, NULL);
412

413
	submodule->path = NULL;
414
	submodule->url = NULL;
415
	submodule->update_strategy.type = SM_UPDATE_UNSPECIFIED;
416
	submodule->update_strategy.command = NULL;
417
	submodule->fetch_recurse = RECURSE_SUBMODULES_NONE;
418
	submodule->ignore = NULL;
419
	submodule->branch = NULL;
420
	submodule->recommend_shallow = -1;
421

422
	oidcpy(&submodule->gitmodules_oid, gitmodules_oid);
423

424
	cache_add(cache, submodule);
425

426
	return submodule;
427
}
428

429
static int parse_fetch_recurse(const char *opt, const char *arg,
430
			       int die_on_error)
431
{
432
	switch (git_parse_maybe_bool(arg)) {
433
	case 1:
434
		return RECURSE_SUBMODULES_ON;
435
	case 0:
436
		return RECURSE_SUBMODULES_OFF;
437
	default:
438
		if (!strcmp(arg, "on-demand"))
439
			return RECURSE_SUBMODULES_ON_DEMAND;
440
		/*
441
		 * Please update $__git_fetch_recurse_submodules in
442
		 * git-completion.bash when you add new options.
443
		 */
444
		if (die_on_error)
445
			die("bad %s argument: %s", opt, arg);
446
		else
447
			return RECURSE_SUBMODULES_ERROR;
448
	}
449
}
450

451
int parse_submodule_fetchjobs(const char *var, const char *value,
452
			      const struct key_value_info *kvi)
453
{
454
	int fetchjobs = git_config_int(var, value, kvi);
455
	if (fetchjobs < 0)
456
		die(_("negative values not allowed for submodule.fetchJobs"));
457
	if (!fetchjobs)
458
		fetchjobs = online_cpus();
459
	return fetchjobs;
460
}
461

462
int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
463
{
464
	return parse_fetch_recurse(opt, arg, 1);
465
}
466

467
int option_fetch_parse_recurse_submodules(const struct option *opt,
468
					  const char *arg, int unset)
469
{
470
	int *v;
471

472
	if (!opt->value)
473
		return -1;
474

475
	v = opt->value;
476

477
	if (unset) {
478
		*v = RECURSE_SUBMODULES_OFF;
479
	} else {
480
		if (arg)
481
			*v = parse_fetch_recurse_submodules_arg(opt->long_name, arg);
482
		else
483
			*v = RECURSE_SUBMODULES_ON;
484
	}
485
	return 0;
486
}
487

488
static int parse_update_recurse(const char *opt, const char *arg,
489
				int die_on_error)
490
{
491
	switch (git_parse_maybe_bool(arg)) {
492
	case 1:
493
		return RECURSE_SUBMODULES_ON;
494
	case 0:
495
		return RECURSE_SUBMODULES_OFF;
496
	default:
497
		if (die_on_error)
498
			die("bad %s argument: %s", opt, arg);
499
		return RECURSE_SUBMODULES_ERROR;
500
	}
501
}
502

503
int parse_update_recurse_submodules_arg(const char *opt, const char *arg)
504
{
505
	return parse_update_recurse(opt, arg, 1);
506
}
507

508
static int parse_push_recurse(const char *opt, const char *arg,
509
			       int die_on_error)
510
{
511
	switch (git_parse_maybe_bool(arg)) {
512
	case 1:
513
		/* There's no simple "on" value when pushing */
514
		if (die_on_error)
515
			die("bad %s argument: %s", opt, arg);
516
		else
517
			return RECURSE_SUBMODULES_ERROR;
518
	case 0:
519
		return RECURSE_SUBMODULES_OFF;
520
	default:
521
		if (!strcmp(arg, "on-demand"))
522
			return RECURSE_SUBMODULES_ON_DEMAND;
523
		else if (!strcmp(arg, "check"))
524
			return RECURSE_SUBMODULES_CHECK;
525
		else if (!strcmp(arg, "only"))
526
			return RECURSE_SUBMODULES_ONLY;
527
		/*
528
		 * Please update $__git_push_recurse_submodules in
529
		 * git-completion.bash when you add new modes.
530
		 */
531
		else if (die_on_error)
532
			die("bad %s argument: %s", opt, arg);
533
		else
534
			return RECURSE_SUBMODULES_ERROR;
535
	}
536
}
537

538
int parse_push_recurse_submodules_arg(const char *opt, const char *arg)
539
{
540
	return parse_push_recurse(opt, arg, 1);
541
}
542

543
static void warn_multiple_config(const struct object_id *treeish_name,
544
				 const char *name, const char *option)
545
{
546
	const char *commit_string = "WORKTREE";
547
	if (treeish_name)
548
		commit_string = oid_to_hex(treeish_name);
549
	warning("%s:.gitmodules, multiple configurations found for "
550
			"'submodule.%s.%s'. Skipping second one!",
551
			commit_string, name, option);
552
}
553

554
static void warn_command_line_option(const char *var, const char *value)
555
{
556
	warning(_("ignoring '%s' which may be interpreted as"
557
		  " a command-line option: %s"), var, value);
558
}
559

560
struct parse_config_parameter {
561
	struct submodule_cache *cache;
562
	const struct object_id *treeish_name;
563
	const struct object_id *gitmodules_oid;
564
	int overwrite;
565
};
566

567
/*
568
 * Parse a config item from .gitmodules.
569
 *
570
 * This does not handle submodule-related configuration from the main
571
 * config store (.git/config, etc).  Callers are responsible for
572
 * checking for overrides in the main config store when appropriate.
573
 */
574
static int parse_config(const char *var, const char *value,
575
			const struct config_context *ctx UNUSED, void *data)
576
{
577
	struct parse_config_parameter *me = data;
578
	struct submodule *submodule;
579
	struct strbuf name = STRBUF_INIT, item = STRBUF_INIT;
580
	int ret = 0;
581

582
	/* this also ensures that we only parse submodule entries */
583
	if (!name_and_item_from_var(var, &name, &item))
584
		return 0;
585

586
	submodule = lookup_or_create_by_name(me->cache,
587
					     me->gitmodules_oid,
588
					     name.buf);
589

590
	if (!strcmp(item.buf, "path")) {
591
		if (!value)
592
			ret = config_error_nonbool(var);
593
		else if (looks_like_command_line_option(value))
594
			warn_command_line_option(var, value);
595
		else if (!me->overwrite && submodule->path)
596
			warn_multiple_config(me->treeish_name, submodule->name,
597
					"path");
598
		else {
599
			if (submodule->path)
600
				cache_remove_path(me->cache, submodule);
601
			free((void *) submodule->path);
602
			submodule->path = xstrdup(value);
603
			cache_put_path(me->cache, submodule);
604
		}
605
	} else if (!strcmp(item.buf, "fetchrecursesubmodules")) {
606
		/* when parsing worktree configurations we can die early */
607
		int die_on_error = is_null_oid(me->gitmodules_oid);
608
		if (!me->overwrite &&
609
		    submodule->fetch_recurse != RECURSE_SUBMODULES_NONE)
610
			warn_multiple_config(me->treeish_name, submodule->name,
611
					"fetchrecursesubmodules");
612
		else
613
			submodule->fetch_recurse = parse_fetch_recurse(
614
								var, value,
615
								die_on_error);
616
	} else if (!strcmp(item.buf, "ignore")) {
617
		if (!value)
618
			ret = config_error_nonbool(var);
619
		else if (!me->overwrite && submodule->ignore)
620
			warn_multiple_config(me->treeish_name, submodule->name,
621
					"ignore");
622
		else if (strcmp(value, "untracked") &&
623
			 strcmp(value, "dirty") &&
624
			 strcmp(value, "all") &&
625
			 strcmp(value, "none"))
626
			warning("Invalid parameter '%s' for config option "
627
					"'submodule.%s.ignore'", value, name.buf);
628
		else {
629
			free((void *) submodule->ignore);
630
			submodule->ignore = xstrdup(value);
631
		}
632
	} else if (!strcmp(item.buf, "url")) {
633
		if (!value) {
634
			ret = config_error_nonbool(var);
635
		} else if (looks_like_command_line_option(value)) {
636
			warn_command_line_option(var, value);
637
		} else if (!me->overwrite && submodule->url) {
638
			warn_multiple_config(me->treeish_name, submodule->name,
639
					"url");
640
		} else {
641
			free((void *) submodule->url);
642
			submodule->url = xstrdup(value);
643
		}
644
	} else if (!strcmp(item.buf, "update")) {
645
		if (!value)
646
			ret = config_error_nonbool(var);
647
		else if (!me->overwrite &&
648
			 submodule->update_strategy.type != SM_UPDATE_UNSPECIFIED)
649
			warn_multiple_config(me->treeish_name, submodule->name,
650
					     "update");
651
		else if (parse_submodule_update_strategy(value,
652
			 &submodule->update_strategy) < 0 ||
653
			 submodule->update_strategy.type == SM_UPDATE_COMMAND)
654
			die(_("invalid value for '%s'"), var);
655
	} else if (!strcmp(item.buf, "shallow")) {
656
		if (!me->overwrite && submodule->recommend_shallow != -1)
657
			warn_multiple_config(me->treeish_name, submodule->name,
658
					     "shallow");
659
		else
660
			submodule->recommend_shallow =
661
				git_config_bool(var, value);
662
	} else if (!strcmp(item.buf, "branch")) {
663
		if (!value)
664
			ret = config_error_nonbool(var);
665
		else if (!me->overwrite && submodule->branch)
666
			warn_multiple_config(me->treeish_name, submodule->name,
667
					     "branch");
668
		else {
669
			free((void *)submodule->branch);
670
			submodule->branch = xstrdup(value);
671
		}
672
	}
673

674
	strbuf_release(&name);
675
	strbuf_release(&item);
676

677
	return ret;
678
}
679

680
static int gitmodule_oid_from_commit(const struct object_id *treeish_name,
681
				     struct object_id *gitmodules_oid,
682
				     struct strbuf *rev)
683
{
684
	int ret = 0;
685

686
	if (is_null_oid(treeish_name)) {
687
		oidclr(gitmodules_oid, the_repository->hash_algo);
688
		return 1;
689
	}
690

691
	strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name));
692
	if (repo_get_oid(the_repository, rev->buf, gitmodules_oid) >= 0)
693
		ret = 1;
694

695
	return ret;
696
}
697

698
/* This does a lookup of a submodule configuration by name or by path
699
 * (key) with on-demand reading of the appropriate .gitmodules from
700
 * revisions.
701
 */
702
static const struct submodule *config_from(struct submodule_cache *cache,
703
		const struct object_id *treeish_name, const char *key,
704
		enum lookup_type lookup_type)
705
{
706
	struct strbuf rev = STRBUF_INIT;
707
	unsigned long config_size;
708
	char *config = NULL;
709
	struct object_id oid;
710
	enum object_type type;
711
	const struct submodule *submodule = NULL;
712
	struct parse_config_parameter parameter;
713

714
	/*
715
	 * If any parameter except the cache is a NULL pointer just
716
	 * return the first submodule. Can be used to check whether
717
	 * there are any submodules parsed.
718
	 */
719
	if (!treeish_name || !key) {
720
		struct hashmap_iter iter;
721
		struct submodule_entry *entry;
722

723
		entry = hashmap_iter_first_entry(&cache->for_name, &iter,
724
						struct submodule_entry,
725
						ent /* member name */);
726
		if (!entry)
727
			return NULL;
728
		return entry->config;
729
	}
730

731
	if (!gitmodule_oid_from_commit(treeish_name, &oid, &rev))
732
		goto out;
733

734
	switch (lookup_type) {
735
	case lookup_name:
736
		submodule = cache_lookup_name(cache, &oid, key);
737
		break;
738
	case lookup_path:
739
		submodule = cache_lookup_path(cache, &oid, key);
740
		break;
741
	}
742
	if (submodule)
743
		goto out;
744

745
	config = repo_read_object_file(the_repository, &oid, &type,
746
				       &config_size);
747
	if (!config || type != OBJ_BLOB)
748
		goto out;
749

750
	/* fill the submodule config into the cache */
751
	parameter.cache = cache;
752
	parameter.treeish_name = treeish_name;
753
	parameter.gitmodules_oid = &oid;
754
	parameter.overwrite = 0;
755
	git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
756
			    config, config_size, &parameter, CONFIG_SCOPE_UNKNOWN, NULL);
757
	strbuf_release(&rev);
758
	free(config);
759

760
	switch (lookup_type) {
761
	case lookup_name:
762
		return cache_lookup_name(cache, &oid, key);
763
	case lookup_path:
764
		return cache_lookup_path(cache, &oid, key);
765
	default:
766
		return NULL;
767
	}
768

769
out:
770
	strbuf_release(&rev);
771
	free(config);
772
	return submodule;
773
}
774

775
static void submodule_cache_check_init(struct repository *repo)
776
{
777
	if (repo->submodule_cache && repo->submodule_cache->initialized)
778
		return;
779

780
	if (!repo->submodule_cache)
781
		repo->submodule_cache = submodule_cache_alloc();
782

783
	submodule_cache_init(repo->submodule_cache);
784
}
785

786
/*
787
 * Note: This function is private for a reason, the '.gitmodules' file should
788
 * not be used as a mechanism to retrieve arbitrary configuration stored in
789
 * the repository.
790
 *
791
 * Runs the provided config function on the '.gitmodules' file found in the
792
 * working directory.
793
 */
794
static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
795
{
796
	if (repo->worktree) {
797
		struct git_config_source config_source = {
798
			0, .scope = CONFIG_SCOPE_SUBMODULE
799
		};
800
		const struct config_options opts = { 0 };
801
		struct object_id oid;
802
		char *file;
803
		char *oidstr = NULL;
804

805
		file = repo_worktree_path(repo, GITMODULES_FILE);
806
		if (file_exists(file)) {
807
			config_source.file = file;
808
		} else if (repo_get_oid(repo, GITMODULES_INDEX, &oid) >= 0 ||
809
			   repo_get_oid(repo, GITMODULES_HEAD, &oid) >= 0) {
810
			config_source.blob = oidstr = xstrdup(oid_to_hex(&oid));
811
			if (repo != the_repository)
812
				add_submodule_odb_by_path(repo->objects->odb->path);
813
		} else {
814
			goto out;
815
		}
816

817
		config_with_options(fn, data, &config_source, repo, &opts);
818

819
out:
820
		free(oidstr);
821
		free(file);
822
	}
823
}
824

825
static int gitmodules_cb(const char *var, const char *value,
826
			 const struct config_context *ctx, void *data)
827
{
828
	struct repository *repo = data;
829
	struct parse_config_parameter parameter;
830

831
	parameter.cache = repo->submodule_cache;
832
	parameter.treeish_name = NULL;
833
	parameter.gitmodules_oid = null_oid();
834
	parameter.overwrite = 1;
835

836
	return parse_config(var, value, ctx, &parameter);
837
}
838

839
void repo_read_gitmodules(struct repository *repo, int skip_if_read)
840
{
841
	submodule_cache_check_init(repo);
842

843
	if (repo->submodule_cache->gitmodules_read && skip_if_read)
844
		return;
845

846
	if (repo_read_index(repo) < 0)
847
		return;
848

849
	if (!is_gitmodules_unmerged(repo->index))
850
		config_from_gitmodules(gitmodules_cb, repo, repo);
851

852
	repo->submodule_cache->gitmodules_read = 1;
853
}
854

855
void gitmodules_config_oid(const struct object_id *commit_oid)
856
{
857
	struct strbuf rev = STRBUF_INIT;
858
	struct object_id oid;
859

860
	submodule_cache_check_init(the_repository);
861

862
	if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
863
		git_config_from_blob_oid(gitmodules_cb, rev.buf,
864
					 the_repository, &oid, the_repository,
865
					 CONFIG_SCOPE_UNKNOWN);
866
	}
867
	strbuf_release(&rev);
868

869
	the_repository->submodule_cache->gitmodules_read = 1;
870
}
871

872
const struct submodule *submodule_from_name(struct repository *r,
873
					    const struct object_id *treeish_name,
874
		const char *name)
875
{
876
	repo_read_gitmodules(r, 1);
877
	return config_from(r->submodule_cache, treeish_name, name, lookup_name);
878
}
879

880
const struct submodule *submodule_from_path(struct repository *r,
881
					    const struct object_id *treeish_name,
882
		const char *path)
883
{
884
	repo_read_gitmodules(r, 1);
885
	return config_from(r->submodule_cache, treeish_name, path, lookup_path);
886
}
887

888
/**
889
 * Used internally by submodules_of_tree(). Recurses into 'treeish_name'
890
 * and appends submodule entries to 'out'. The submodule_cache expects
891
 * a root-level treeish_name and paths, so keep track of these values
892
 * with 'root_tree' and 'prefix'.
893
 */
894
static void traverse_tree_submodules(struct repository *r,
895
				     const struct object_id *root_tree,
896
				     char *prefix,
897
				     const struct object_id *treeish_name,
898
				     struct submodule_entry_list *out)
899
{
900
	struct tree_desc tree;
901
	struct submodule_tree_entry *st_entry;
902
	struct name_entry name_entry;
903
	char *tree_path = NULL;
904

905
	fill_tree_descriptor(r, &tree, treeish_name);
906
	while (tree_entry(&tree, &name_entry)) {
907
		if (prefix)
908
			tree_path =
909
				mkpathdup("%s/%s", prefix, name_entry.path);
910
		else
911
			tree_path = xstrdup(name_entry.path);
912

913
		if (S_ISGITLINK(name_entry.mode) &&
914
		    is_tree_submodule_active(r, root_tree, tree_path)) {
915
			ALLOC_GROW(out->entries, out->entry_nr + 1,
916
				   out->entry_alloc);
917
			st_entry = &out->entries[out->entry_nr++];
918

919
			st_entry->name_entry = xmalloc(sizeof(*st_entry->name_entry));
920
			*st_entry->name_entry = name_entry;
921
			st_entry->submodule =
922
				submodule_from_path(r, root_tree, tree_path);
923
			st_entry->repo = xmalloc(sizeof(*st_entry->repo));
924
			if (repo_submodule_init(st_entry->repo, r, tree_path,
925
						root_tree))
926
				FREE_AND_NULL(st_entry->repo);
927

928
		} else if (S_ISDIR(name_entry.mode))
929
			traverse_tree_submodules(r, root_tree, tree_path,
930
						 &name_entry.oid, out);
931
		free(tree_path);
932
	}
933
}
934

935
void submodules_of_tree(struct repository *r,
936
			const struct object_id *treeish_name,
937
			struct submodule_entry_list *out)
938
{
939
	CALLOC_ARRAY(out->entries, 0);
940
	out->entry_nr = 0;
941
	out->entry_alloc = 0;
942

943
	traverse_tree_submodules(r, treeish_name, NULL, treeish_name, out);
944
}
945

946
void submodule_free(struct repository *r)
947
{
948
	if (r->submodule_cache)
949
		submodule_cache_clear(r->submodule_cache);
950
}
951

952
static int config_print_callback(const char *var, const char *value,
953
				 const struct config_context *ctx UNUSED,
954
				 void *cb_data)
955
{
956
	char *wanted_key = cb_data;
957

958
	if (!strcmp(wanted_key, var))
959
		printf("%s\n", value);
960

961
	return 0;
962
}
963

964
int print_config_from_gitmodules(struct repository *repo, const char *key)
965
{
966
	int ret;
967
	char *store_key;
968

969
	ret = git_config_parse_key(key, &store_key, NULL);
970
	if (ret < 0)
971
		return CONFIG_INVALID_KEY;
972

973
	config_from_gitmodules(config_print_callback, repo, store_key);
974

975
	free(store_key);
976
	return 0;
977
}
978

979
int config_set_in_gitmodules_file_gently(const char *key, const char *value)
980
{
981
	int ret;
982

983
	ret = git_config_set_in_file_gently(GITMODULES_FILE, key, NULL, value);
984
	if (ret < 0)
985
		/* Maybe the user already did that, don't error out here */
986
		warning(_("Could not update .gitmodules entry %s"), key);
987

988
	return ret;
989
}
990

991
struct fetch_config {
992
	int *max_children;
993
	int *recurse_submodules;
994
};
995

996
static int gitmodules_fetch_config(const char *var, const char *value,
997
				   const struct config_context *ctx,
998
				   void *cb)
999
{
1000
	struct fetch_config *config = cb;
1001
	if (!strcmp(var, "submodule.fetchjobs")) {
1002
		if (config->max_children)
1003
			*(config->max_children) =
1004
				parse_submodule_fetchjobs(var, value, ctx->kvi);
1005
		return 0;
1006
	} else if (!strcmp(var, "fetch.recursesubmodules")) {
1007
		if (config->recurse_submodules)
1008
			*(config->recurse_submodules) =
1009
				parse_fetch_recurse_submodules_arg(var, value);
1010
		return 0;
1011
	}
1012

1013
	return 0;
1014
}
1015

1016
void fetch_config_from_gitmodules(int *max_children, int *recurse_submodules)
1017
{
1018
	struct fetch_config config = {
1019
		.max_children = max_children,
1020
		.recurse_submodules = recurse_submodules
1021
	};
1022
	config_from_gitmodules(gitmodules_fetch_config, the_repository, &config);
1023
}
1024

1025
static int gitmodules_update_clone_config(const char *var, const char *value,
1026
					  const struct config_context *ctx,
1027
					  void *cb)
1028
{
1029
	int *max_jobs = cb;
1030
	if (!strcmp(var, "submodule.fetchjobs"))
1031
		*max_jobs = parse_submodule_fetchjobs(var, value, ctx->kvi);
1032
	return 0;
1033
}
1034

1035
void update_clone_config_from_gitmodules(int *max_jobs)
1036
{
1037
	config_from_gitmodules(gitmodules_update_clone_config, the_repository, &max_jobs);
1038
}
1039

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.