repository.c 80.8 KB
Newer Older
1
/*
Edward Thomson committed
2
 * Copyright (C) the libgit2 contributors. All rights reserved.
3
 *
Vicent Marti committed
4 5
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
6
 */
7 8 9

#include "repository.h"

10
#include <ctype.h>
11

12
#include "git2/object.h"
13
#include "git2/sys/repository.h"
14

15
#include "buf.h"
16 17 18
#include "common.h"
#include "commit.h"
#include "tag.h"
19
#include "blob.h"
20
#include "futils.h"
21
#include "sysdir.h"
22 23
#include "filebuf.h"
#include "index.h"
24
#include "config.h"
25
#include "refs.h"
26 27
#include "filter.h"
#include "odb.h"
28
#include "refdb.h"
29
#include "remote.h"
Edward Thomson committed
30
#include "merge.h"
31
#include "diff_driver.h"
32
#include "annotated_commit.h"
33
#include "submodule.h"
34
#include "worktree.h"
35
#include "path.h"
36
#include "strmap.h"
37

38 39 40 41
#ifdef GIT_WIN32
# include "win32/w32_util.h"
#endif

42
bool git_repository__validate_ownership = true;
43 44
bool git_repository__fsync_gitdir = false;

45 46
static const struct {
    git_repository_item_t parent;
47
	git_repository_item_t fallback;
48 49 50
    const char *name;
    bool directory;
} items[] = {
51 52 53 54 55 56 57 58 59 60 61 62 63 64
	{ GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true },
	{ GIT_REPOSITORY_ITEM_WORKDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true },
	{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true },
	{ GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, "index", false },
	{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "objects", true },
	{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "refs", true },
	{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "packed-refs", false },
	{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "remotes", true },
	{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "config", false },
	{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "info", true },
	{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "hooks", true },
	{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "logs", true },
	{ GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, "modules", true },
	{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "worktrees", true }
65 66
};

67 68
static int check_repositoryformatversion(int *version, git_config *config);
static int check_extensions(git_config *config, int version);
69
static int load_global_config(git_config **config);
70

71
#define GIT_COMMONDIR_FILE "commondir"
72
#define GIT_GITDIR_FILE "gitdir"
73

74
#define GIT_FILE_CONTENT_PREFIX "gitdir:"
75

76
#define GIT_BRANCH_DEFAULT "master"
77

78
#define GIT_REPO_VERSION 0
79
#define GIT_REPO_MAX_VERSION 1
80

81
git_str git_repository__reserved_names_win32[] = {
82 83 84 85 86
	{ DOT_GIT, 0, CONST_STRLEN(DOT_GIT) },
	{ GIT_DIR_SHORTNAME, 0, CONST_STRLEN(GIT_DIR_SHORTNAME) }
};
size_t git_repository__reserved_names_win32_len = 2;

87
git_str git_repository__reserved_names_posix[] = {
88 89 90
	{ DOT_GIT, 0, CONST_STRLEN(DOT_GIT) },
};
size_t git_repository__reserved_names_posix_len = 1;
91

92
static void set_odb(git_repository *repo, git_odb *odb)
93
{
94 95 96 97 98
	if (odb) {
		GIT_REFCOUNT_OWN(odb, repo);
		GIT_REFCOUNT_INC(odb);
	}

99
	if ((odb = git_atomic_swap(repo->_odb, odb)) != NULL) {
100 101
		GIT_REFCOUNT_OWN(odb, NULL);
		git_odb_free(odb);
102
	}
103
}
104

105
static void set_refdb(git_repository *repo, git_refdb *refdb)
106
{
107 108 109 110 111
	if (refdb) {
		GIT_REFCOUNT_OWN(refdb, repo);
		GIT_REFCOUNT_INC(refdb);
	}

112
	if ((refdb = git_atomic_swap(repo->_refdb, refdb)) != NULL) {
113 114
		GIT_REFCOUNT_OWN(refdb, NULL);
		git_refdb_free(refdb);
115 116 117
	}
}

118
static void set_config(git_repository *repo, git_config *config)
119
{
120 121 122 123 124
	if (config) {
		GIT_REFCOUNT_OWN(config, repo);
		GIT_REFCOUNT_INC(config);
	}

125
	if ((config = git_atomic_swap(repo->_config, config)) != NULL) {
126 127
		GIT_REFCOUNT_OWN(config, NULL);
		git_config_free(config);
128
	}
129

130
	git_repository__configmap_lookup_cache_clear(repo);
131 132
}

133
static void set_index(git_repository *repo, git_index *index)
134
{
135 136 137 138 139
	if (index) {
		GIT_REFCOUNT_OWN(index, repo);
		GIT_REFCOUNT_INC(index);
	}

140
	if ((index = git_atomic_swap(repo->_index, index)) != NULL) {
141 142
		GIT_REFCOUNT_OWN(index, NULL);
		git_index_free(index);
143
	}
144 145
}

146
int git_repository__cleanup(git_repository *repo)
147
{
148
	GIT_ASSERT_ARG(repo);
149

150
	git_repository_submodule_cache_clear(repo);
151
	git_cache_clear(&repo->objects);
152
	git_attr_cache_flush(repo);
153

154 155 156 157
	set_config(repo, NULL);
	set_index(repo, NULL);
	set_odb(repo, NULL);
	set_refdb(repo, NULL);
158 159

	return 0;
160 161 162 163
}

void git_repository_free(git_repository *repo)
{
164 165
	size_t i;

166 167 168 169 170
	if (repo == NULL)
		return;

	git_repository__cleanup(repo);

171
	git_cache_dispose(&repo->objects);
172

173
	git_diff_driver_registry_free(repo->diff_drivers);
174
	repo->diff_drivers = NULL;
175

176
	for (i = 0; i < repo->reserved_names.size; i++)
177
		git_str_dispose(git_array_get(repo->reserved_names, i));
Edward Thomson committed
178
	git_array_clear(repo->reserved_names);
179

180 181
	git__free(repo->gitlink);
	git__free(repo->gitdir);
182
	git__free(repo->commondir);
Russell Belfer committed
183
	git__free(repo->workdir);
Vicent Marti committed
184
	git__free(repo->namespace);
185 186
	git__free(repo->ident_name);
	git__free(repo->ident_email);
Russell Belfer committed
187

188
	git__memzero(repo, sizeof(*repo));
189
	git__free(repo);
190 191
}

192
/* Check if we have a separate commondir (e.g. we have a worktree) */
193
static int lookup_commondir(bool *separate, git_str *commondir, git_str *repository_path)
194
{
195
	git_str common_link  = GIT_STR_INIT;
196 197 198 199 200 201
	int error;

	/*
	 * If there's no commondir file, the repository path is the
	 * common path, but it needs a trailing slash.
	 */
202
	if (!git_fs_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) {
203
		if ((error = git_str_set(commondir, repository_path->ptr, repository_path->size)) == 0)
204
		    error = git_fs_path_to_dir(commondir);
205

206
		*separate = false;
207 208 209
		goto done;
	}

210 211
	*separate = true;

212
	if ((error = git_str_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE)) < 0 ||
213 214 215
	    (error = git_futils_readbuffer(&common_link, common_link.ptr)) < 0)
		goto done;

216
	git_str_rtrim(&common_link);
217
	if (git_fs_path_is_relative(common_link.ptr)) {
218
		if ((error = git_str_joinpath(commondir, repository_path->ptr, common_link.ptr)) < 0)
219 220
			goto done;
	} else {
221
		git_str_swap(commondir, &common_link);
222 223
	}

224
	git_str_dispose(&common_link);
225 226

	/* Make sure the commondir path always has a trailing slash */
227
	error = git_fs_path_prettify_dir(commondir, commondir->ptr, NULL);
228 229 230 231 232

done:
	return error;
}

233
GIT_INLINE(int) validate_repo_path(git_str *path)
234 235 236 237 238 239 240 241 242 243 244
{
	/*
	 * The longest static path in a repository (or commondir) is the
	 * packed refs file.  (Loose refs may be longer since they
	 * include the reference name, but will be validated when the
	 * path is constructed.)
	 */
	static size_t suffix_len =
		CONST_STRLEN("objects/pack/pack-.pack.lock") +
		GIT_OID_HEXSZ;

245 246
	return git_fs_path_validate_str_length_with_suffix(
		path, suffix_len);
247 248
}

249 250 251 252 253
/*
 * Git repository open methods
 *
 * Open a repository object from its path
 */
254
static int is_valid_repository_path(bool *out, git_str *repository_path, git_str *common_path)
255
{
256
	bool separate_commondir = false;
257 258 259 260
	int error;

	*out = false;

261
	if ((error = lookup_commondir(&separate_commondir, common_path, repository_path)) < 0)
262
		return error;
263

264
	/* Ensure HEAD file exists */
265
	if (git_fs_path_contains_file(repository_path, GIT_HEAD_FILE) == false)
266
		return 0;
267

268
	/* Check files in common dir */
269
	if (git_fs_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false)
270
		return 0;
271
	if (git_fs_path_contains_dir(common_path, GIT_REFS_DIR) == false)
272
		return 0;
273

274 275 276 277 278 279
	/* Ensure the repo (and commondir) are valid paths */
	if ((error = validate_repo_path(common_path)) < 0 ||
	    (separate_commondir &&
	     (error = validate_repo_path(repository_path)) < 0))
		return error;

280 281
	*out = true;
	return 0;
282 283
}

284
static git_repository *repository_alloc(void)
285
{
286
	git_repository *repo = git__calloc(1, sizeof(git_repository));
287

288 289 290 291 292 293 294
	if (repo == NULL ||
		git_cache_init(&repo->objects) < 0)
		goto on_error;

	git_array_init_to_size(repo->reserved_names, 4);
	if (!repo->reserved_names.ptr)
		goto on_error;
295

296 297
	/* set all the entries in the configmap cache to `unset` */
	git_repository__configmap_lookup_cache_clear(repo);
298

299
	return repo;
300 301 302

on_error:
	if (repo)
303
		git_cache_dispose(&repo->objects);
304 305 306

	git__free(repo);
	return NULL;
307 308
}

309 310
int git_repository_new(git_repository **out)
{
311 312 313
	git_repository *repo;

	*out = repo = repository_alloc();
314
	GIT_ERROR_CHECK_ALLOC(repo);
315 316

	repo->is_bare = 1;
317
	repo->is_worktree = 0;
318

319 320 321
	return 0;
}

322
static int load_config_data(git_repository *repo, const git_config *config)
323
{
324
	int is_bare;
325

326 327 328 329
	int err = git_config_get_bool(&is_bare, config, "core.bare");
	if (err < 0 && err != GIT_ENOTFOUND)
		return err;

330
	/* Try to figure out if it's bare, default to non-bare if it's not set */
331 332
	if (err != GIT_ENOTFOUND)
		repo->is_bare = is_bare && !repo->is_worktree;
333
	else
334
		repo->is_bare = 0;
335

336
	return 0;
337
}
338

339
static int load_workdir(git_repository *repo, git_config *config, git_str *parent_path)
340
{
341
	int error;
342
	git_config_entry *ce;
343 344
	git_str worktree = GIT_STR_INIT;
	git_str path = GIT_STR_INIT;
345

346
	if (repo->is_bare)
347
		return 0;
348

349 350 351
	if ((error = git_config__lookup_entry(
			&ce, config, "core.worktree", false)) < 0)
		return error;
352

353 354 355 356 357 358 359
	if (repo->is_worktree) {
		char *gitlink = git_worktree__read_link(repo->gitdir, GIT_GITDIR_FILE);
		if (!gitlink) {
			error = -1;
			goto cleanup;
		}

360
		git_str_attach(&worktree, gitlink, 0);
361

362 363
		if ((git_fs_path_dirname_r(&worktree, worktree.ptr)) < 0 ||
		    git_fs_path_to_dir(&worktree) < 0) {
364 365 366 367
			error = -1;
			goto cleanup;
		}

368
		repo->workdir = git_str_detach(&worktree);
369 370
	}
	else if (ce && ce->value) {
371
		if ((error = git_fs_path_prettify_dir(
372
				&worktree, ce->value, repo->gitdir)) < 0)
373
			goto cleanup;
374

375
		repo->workdir = git_str_detach(&worktree);
376
	}
377
	else if (parent_path && git_fs_path_isdir(parent_path->ptr))
378
		repo->workdir = git_str_detach(parent_path);
379
	else {
380 381
		if (git_fs_path_dirname_r(&worktree, repo->gitdir) < 0 ||
		    git_fs_path_to_dir(&worktree) < 0) {
382 383 384
			error = -1;
			goto cleanup;
		}
385

386
		repo->workdir = git_str_detach(&worktree);
387 388
	}

389
	GIT_ERROR_CHECK_ALLOC(repo->workdir);
390
cleanup:
391
	git_str_dispose(&path);
392 393
	git_config_entry_free(ce);
	return error;
394 395
}

396 397 398 399
/*
 * This function returns furthest offset into path where a ceiling dir
 * is found, so we can stop processing the path at that point.
 *
400
 * Note: converting this to use git_strs instead of GIT_PATH_MAX buffers on
401 402 403
 * the stack could remove directories name limits, but at the cost of doing
 * repeated malloc/frees inside the loop below, so let's not do it now.
 */
404
static size_t find_ceiling_dir_offset(
405 406 407 408 409 410
	const char *path,
	const char *ceiling_directories)
{
	char buf[GIT_PATH_MAX + 1];
	char buf2[GIT_PATH_MAX + 1];
	const char *ceil, *sep;
411
	size_t len, max_len = 0, min_len;
412

413
	GIT_ASSERT_ARG(path);
414

415
	min_len = (size_t)(git_fs_path_root(path) + 1);
416 417

	if (ceiling_directories == NULL || min_len == 0)
418
		return min_len;
419 420 421 422 423

	for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) {
		for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);
		len = sep - ceil;

424
		if (len == 0 || len >= sizeof(buf) || git_fs_path_root(ceil) == -1)
425 426 427 428 429 430 431 432 433 434 435 436 437
			continue;

		strncpy(buf, ceil, len);
		buf[len] = '\0';

		if (p_realpath(buf, buf2) == NULL)
			continue;

		len = strlen(buf2);
		if (len > 0 && buf2[len-1] == '/')
			buf[--len] = '\0';

		if (!strncmp(path, buf2, len) &&
438
			(path[len] == '/' || !path[len]) &&
439 440 441 442 443 444
			len > max_len)
		{
			max_len = len;
		}
	}

445
	return (max_len <= min_len ? min_len : max_len);
446 447 448 449 450 451 452
}

/*
 * Read the contents of `file_path` and set `path_out` to the repo dir that
 * it points to.  Before calling, set `path_out` to the base directory that
 * should be used if the contents of `file_path` are a relative path.
 */
453
static int read_gitfile(git_str *path_out, const char *file_path)
454 455
{
	int     error = 0;
456
	git_str file = GIT_STR_INIT;
457 458
	size_t  prefix_len = strlen(GIT_FILE_CONTENT_PREFIX);

459 460
	GIT_ASSERT_ARG(path_out);
	GIT_ASSERT_ARG(file_path);
461 462 463 464

	if (git_futils_readbuffer(&file, file_path) < 0)
		return -1;

465
	git_str_rtrim(&file);
466
	/* apparently on Windows, some people use backslashes in paths */
467
	git_fs_path_mkposix(file.ptr);
468

469 470
	if (git_str_len(&file) <= prefix_len ||
		memcmp(git_str_cstr(&file), GIT_FILE_CONTENT_PREFIX, prefix_len) != 0)
471
	{
472
		git_error_set(GIT_ERROR_REPOSITORY,
473
			"the `.git` file at '%s' is malformed", file_path);
474 475
		error = -1;
	}
476
	else if ((error = git_fs_path_dirname_r(path_out, file_path)) >= 0) {
477
		const char *gitlink = git_str_cstr(&file) + prefix_len;
478
		while (*gitlink && git__isspace(*gitlink)) gitlink++;
479

480
		error = git_fs_path_prettify_dir(
481
			path_out, gitlink, git_str_cstr(path_out));
482 483
	}

484
	git_str_dispose(&file);
485 486 487
	return error;
}

488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
typedef struct {
	const char *repo_path;
	git_str tmp;
	bool is_safe;
} validate_ownership_data;

static int validate_ownership_cb(const git_config_entry *entry, void *payload)
{
	validate_ownership_data *data = payload;

	if (strcmp(entry->value, "") == 0)
		data->is_safe = false;

	if (git_fs_path_prettify_dir(&data->tmp, entry->value, NULL) == 0 &&
	    strcmp(data->tmp.ptr, data->repo_path) == 0)
		data->is_safe = true;

	return 0;
}

508 509
static int validate_ownership(const char *repo_path)
{
510 511
	git_config *config = NULL;
	validate_ownership_data data = { repo_path, GIT_STR_INIT, false };
512 513 514
	bool is_safe;
	int error;

515
	if ((error = git_fs_path_owner_is_current_user(&is_safe, repo_path)) < 0) {
516 517
		if (error == GIT_ENOTFOUND)
			error = 0;
518

519 520 521 522 523 524 525 526 527 528 529 530 531 532
		goto done;
	}

	if (is_safe) {
		error = 0;
		goto done;
	}

	if (load_global_config(&config) == 0) {
		error = git_config_get_multivar_foreach(config, "safe.directory", NULL, validate_ownership_cb, &data);

		if (!error && data.is_safe)
			goto done;
	}
533 534 535 536

	git_error_set(GIT_ERROR_CONFIG,
		"repository path '%s' is not owned by current user",
		repo_path);
537 538 539 540 541 542
	error = GIT_EOWNER;

done:
	git_config_free(config);
	git_str_dispose(&data.tmp);
	return error;
543 544
}

545
static int find_repo(
546 547 548 549
	git_str *gitdir_path,
	git_str *workdir_path,
	git_str *gitlink_path,
	git_str *commondir_path,
550 551 552
	const char *start_path,
	uint32_t flags,
	const char *ceiling_dirs)
553
{
554 555 556
	git_str path = GIT_STR_INIT;
	git_str repo_link = GIT_STR_INIT;
	git_str common_link = GIT_STR_INIT;
557 558
	struct stat st;
	dev_t initial_device = 0;
559
	int min_iterations;
560
	bool in_dot_git, is_valid;
561
	size_t ceiling_offset = 0;
562
	int error;
563

564
	git_str_clear(gitdir_path);
565

566
	error = git_fs_path_prettify(&path, start_path, NULL);
567
	if (error < 0)
568 569
		return error;

570 571
	/* in_dot_git toggles each loop:
	 * /a/b/c/.git, /a/b/c, /a/b/.git, /a/b, /a/.git, /a
572 573 574
	 * With GIT_REPOSITORY_OPEN_BARE or GIT_REPOSITORY_OPEN_NO_DOTGIT, we
	 * assume we started with /a/b/c.git and don't append .git the first
	 * time through.
575 576
	 * min_iterations indicates the number of iterations left before going
	 * further counts as a search. */
577
	if (flags & (GIT_REPOSITORY_OPEN_BARE | GIT_REPOSITORY_OPEN_NO_DOTGIT)) {
578 579 580 581 582 583
		in_dot_git = true;
		min_iterations = 1;
	} else {
		in_dot_git = false;
		min_iterations = 2;
	}
584

585
	for (;;) {
586
		if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT)) {
587
			if (!in_dot_git) {
588
				if ((error = git_str_joinpath(&path, path.ptr, DOT_GIT)) < 0)
589
					goto out;
590
			}
591 592
			in_dot_git = !in_dot_git;
		}
593 594 595 596 597 598

		if (p_stat(path.ptr, &st) == 0) {
			/* check that we have not crossed device boundaries */
			if (initial_device == 0)
				initial_device = st.st_dev;
			else if (st.st_dev != initial_device &&
599
				 !(flags & GIT_REPOSITORY_OPEN_CROSS_FS))
600 601 602
				break;

			if (S_ISDIR(st.st_mode)) {
603 604 605 606
				if ((error = is_valid_repository_path(&is_valid, &path, &common_link)) < 0)
					goto out;

				if (is_valid) {
607
					if ((error = git_fs_path_to_dir(&path)) < 0 ||
608
					    (error = git_str_set(gitdir_path, path.ptr, path.size)) < 0)
609
						goto out;
610

611
					if (gitlink_path)
612
						if ((error = git_str_attach(gitlink_path, git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0)) < 0)
613
							goto out;
614
					if (commondir_path)
615
						git_str_swap(&common_link, commondir_path);
616

617 618
					break;
				}
619 620 621 622 623 624
			} else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) {
				if ((error = read_gitfile(&repo_link, path.ptr)) < 0 ||
				    (error = is_valid_repository_path(&is_valid, &repo_link, &common_link)) < 0)
					goto out;

				if (is_valid) {
625
					git_str_swap(gitdir_path, &repo_link);
626

627
					if (gitlink_path)
628
						if ((error = git_str_put(gitlink_path, path.ptr, path.size)) < 0)
629
							goto out;
630
					if (commondir_path)
631
						git_str_swap(&common_link, commondir_path);
632
				}
633
				break;
634 635 636
			}
		}

637 638 639
		/* Move up one directory. If we're in_dot_git, we'll search the
		 * parent itself next. If we're !in_dot_git, we'll search .git
		 * in the parent directory next (added at the top of the loop). */
640
		if ((error = git_fs_path_dirname_r(&path, path.ptr)) < 0)
641
			goto out;
642

643 644 645 646
		/* Once we've checked the directory (and .git if applicable),
		 * find the ceiling for a search. */
		if (min_iterations && (--min_iterations == 0))
			ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs);
647 648

		/* Check if we should stop searching here. */
649 650
		if (min_iterations == 0 &&
		    (path.ptr[ceiling_offset] == 0 || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))
651
			break;
652 653
	}

654
	if (workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
655 656
		if (!git_str_len(gitdir_path))
			git_str_clear(workdir_path);
657 658
		else if ((error = git_fs_path_dirname_r(workdir_path, path.ptr)) < 0 ||
			 (error = git_fs_path_to_dir(workdir_path)) < 0)
659
			goto out;
660 661
	}

662 663
	/* If we didn't find the repository, and we don't have any other error
	 * to report, report that. */
664
	if (!git_str_len(gitdir_path)) {
665
		git_error_set(GIT_ERROR_REPOSITORY, "could not find repository from '%s'", start_path);
666
		error = GIT_ENOTFOUND;
667
		goto out;
668
	}
669

670
out:
671 672 673
	git_str_dispose(&path);
	git_str_dispose(&repo_link);
	git_str_dispose(&common_link);
674 675 676
	return error;
}

677 678 679 680
int git_repository_open_bare(
	git_repository **repo_ptr,
	const char *bare_path)
{
681
	git_str path = GIT_STR_INIT, common_path = GIT_STR_INIT;
682
	git_repository *repo = NULL;
683 684
	bool is_valid;
	int error;
685

686
	if ((error = git_fs_path_prettify_dir(&path, bare_path, NULL)) < 0 ||
687
	    (error = is_valid_repository_path(&is_valid, &path, &common_path)) < 0)
688 689
		return error;

690
	if (!is_valid) {
691 692
		git_str_dispose(&path);
		git_str_dispose(&common_path);
693
		git_error_set(GIT_ERROR_REPOSITORY, "path is not a repository: %s", bare_path);
694 695 696 697
		return GIT_ENOTFOUND;
	}

	repo = repository_alloc();
698
	GIT_ERROR_CHECK_ALLOC(repo);
699

700
	repo->gitdir = git_str_detach(&path);
701
	GIT_ERROR_CHECK_ALLOC(repo->gitdir);
702
	repo->commondir = git_str_detach(&common_path);
703
	GIT_ERROR_CHECK_ALLOC(repo->commondir);
704 705 706

	/* of course we're bare! */
	repo->is_bare = 1;
707
	repo->is_worktree = 0;
708 709 710 711 712 713
	repo->workdir = NULL;

	*repo_ptr = repo;
	return 0;
}

714 715 716 717 718 719 720
static int _git_repository_open_ext_from_env(
	git_repository **out,
	const char *start_path)
{
	git_repository *repo = NULL;
	git_index *index = NULL;
	git_odb *odb = NULL;
721 722 723 724 725 726 727 728 729
	git_str dir_buf = GIT_STR_INIT;
	git_str ceiling_dirs_buf = GIT_STR_INIT;
	git_str across_fs_buf = GIT_STR_INIT;
	git_str index_file_buf = GIT_STR_INIT;
	git_str namespace_buf = GIT_STR_INIT;
	git_str object_dir_buf = GIT_STR_INIT;
	git_str alts_buf = GIT_STR_INIT;
	git_str work_tree_buf = GIT_STR_INIT;
	git_str common_dir_buf = GIT_STR_INIT;
730 731 732 733 734 735 736
	const char *ceiling_dirs = NULL;
	unsigned flags = 0;
	int error;

	if (!start_path) {
		error = git__getenv(&dir_buf, "GIT_DIR");
		if (error == GIT_ENOTFOUND) {
737
			git_error_clear();
738 739 740 741
			start_path = ".";
		} else if (error < 0)
			goto error;
		else {
742
			start_path = git_str_cstr(&dir_buf);
743 744 745 746 747 748 749
			flags |= GIT_REPOSITORY_OPEN_NO_SEARCH;
			flags |= GIT_REPOSITORY_OPEN_NO_DOTGIT;
		}
	}

	error = git__getenv(&ceiling_dirs_buf, "GIT_CEILING_DIRECTORIES");
	if (error == GIT_ENOTFOUND)
750
		git_error_clear();
751 752 753
	else if (error < 0)
		goto error;
	else
754
		ceiling_dirs = git_str_cstr(&ceiling_dirs_buf);
755 756 757

	error = git__getenv(&across_fs_buf, "GIT_DISCOVERY_ACROSS_FILESYSTEM");
	if (error == GIT_ENOTFOUND)
758
		git_error_clear();
759 760 761 762
	else if (error < 0)
		goto error;
	else {
		int across_fs = 0;
763
		error = git_config_parse_bool(&across_fs, git_str_cstr(&across_fs_buf));
764 765 766 767 768 769 770 771
		if (error < 0)
			goto error;
		if (across_fs)
			flags |= GIT_REPOSITORY_OPEN_CROSS_FS;
	}

	error = git__getenv(&index_file_buf, "GIT_INDEX_FILE");
	if (error == GIT_ENOTFOUND)
772
		git_error_clear();
773 774 775
	else if (error < 0)
		goto error;
	else {
776
		error = git_index_open(&index, git_str_cstr(&index_file_buf));
777 778 779 780 781 782
		if (error < 0)
			goto error;
	}

	error = git__getenv(&namespace_buf, "GIT_NAMESPACE");
	if (error == GIT_ENOTFOUND)
783
		git_error_clear();
784 785 786 787 788
	else if (error < 0)
		goto error;

	error = git__getenv(&object_dir_buf, "GIT_OBJECT_DIRECTORY");
	if (error == GIT_ENOTFOUND)
789
		git_error_clear();
790 791 792
	else if (error < 0)
		goto error;
	else {
793
		error = git_odb_open(&odb, git_str_cstr(&object_dir_buf));
794 795 796 797 798 799
		if (error < 0)
			goto error;
	}

	error = git__getenv(&work_tree_buf, "GIT_WORK_TREE");
	if (error == GIT_ENOTFOUND)
800
		git_error_clear();
801 802 803
	else if (error < 0)
		goto error;
	else {
804
		git_error_set(GIT_ERROR_INVALID, "GIT_WORK_TREE unimplemented");
805 806 807 808 809 810
		error = GIT_ERROR;
		goto error;
	}

	error = git__getenv(&work_tree_buf, "GIT_COMMON_DIR");
	if (error == GIT_ENOTFOUND)
811
		git_error_clear();
812 813 814
	else if (error < 0)
		goto error;
	else {
815
		git_error_set(GIT_ERROR_INVALID, "GIT_COMMON_DIR unimplemented");
816 817 818 819 820 821 822 823 824 825 826 827
		error = GIT_ERROR;
		goto error;
	}

	error = git_repository_open_ext(&repo, start_path, flags, ceiling_dirs);
	if (error < 0)
		goto error;

	if (odb)
		git_repository_set_odb(repo, odb);

	error = git__getenv(&alts_buf, "GIT_ALTERNATE_OBJECT_DIRECTORIES");
828
	if (error == GIT_ENOTFOUND) {
829
		git_error_clear();
830 831
		error = 0;
	} else if (error < 0)
832 833 834 835 836 837 838 839 840 841
		goto error;
        else {
		const char *end;
		char *alt, *sep;
		if (!odb) {
			error = git_repository_odb(&odb, repo);
			if (error < 0)
				goto error;
		}

842
		end = git_str_cstr(&alts_buf) + git_str_len(&alts_buf);
843 844 845 846 847 848 849 850 851 852 853
		for (sep = alt = alts_buf.ptr; sep != end; alt = sep+1) {
			for (sep = alt; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++)
				;
			if (*sep)
				*sep = '\0';
			error = git_odb_add_disk_alternate(odb, alt);
			if (error < 0)
				goto error;
		}
	}

854 855
	if (git_str_len(&namespace_buf)) {
		error = git_repository_set_namespace(repo, git_str_cstr(&namespace_buf));
856 857 858
		if (error < 0)
			goto error;
	}
859 860 861 862 863 864 865 866 867 868 869 870

	git_repository_set_index(repo, index);

	if (out) {
		*out = repo;
		goto success;
	}
error:
	git_repository_free(repo);
success:
	git_odb_free(odb);
	git_index_free(index);
871 872 873 874 875 876 877 878 879
	git_str_dispose(&common_dir_buf);
	git_str_dispose(&work_tree_buf);
	git_str_dispose(&alts_buf);
	git_str_dispose(&object_dir_buf);
	git_str_dispose(&namespace_buf);
	git_str_dispose(&index_file_buf);
	git_str_dispose(&across_fs_buf);
	git_str_dispose(&ceiling_dirs_buf);
	git_str_dispose(&dir_buf);
880 881 882
	return error;
}

883 884
static int repo_is_worktree(unsigned *out, const git_repository *repo)
{
885
	git_str gitdir_link = GIT_STR_INIT;
886 887
	int error;

888 889 890 891 892 893 894
	/* Worktrees cannot have the same commondir and gitdir */
	if (repo->commondir && repo->gitdir
	    && !strcmp(repo->commondir, repo->gitdir)) {
		*out = 0;
		return 0;
	}

895
	if ((error = git_str_joinpath(&gitdir_link, repo->gitdir, "gitdir")) < 0)
896 897 898 899
		return -1;

	/* A 'gitdir' file inside a git directory is currently
	 * only used when the repository is a working tree. */
900
	*out = !!git_fs_path_exists(gitdir_link.ptr);
901

902
	git_str_dispose(&gitdir_link);
903 904 905
	return error;
}

906 907 908
int git_repository_open_ext(
	git_repository **repo_ptr,
	const char *start_path,
909
	unsigned int flags,
910 911 912
	const char *ceiling_dirs)
{
	int error;
913
	unsigned is_worktree;
914 915
	git_str gitdir = GIT_STR_INIT, workdir = GIT_STR_INIT,
		gitlink = GIT_STR_INIT, commondir = GIT_STR_INIT;
916
	git_repository *repo = NULL;
917
	git_config *config = NULL;
918
	const char *validation_path;
919
	int version = 0;
920

921 922 923
	if (flags & GIT_REPOSITORY_OPEN_FROM_ENV)
		return _git_repository_open_ext_from_env(repo_ptr, start_path);

924 925
	if (repo_ptr)
		*repo_ptr = NULL;
926

927
	error = find_repo(
928
		&gitdir, &workdir, &gitlink, &commondir, start_path, flags, ceiling_dirs);
929

930 931
	if (error < 0 || !repo_ptr)
		goto cleanup;
932

933
	repo = repository_alloc();
934
	GIT_ERROR_CHECK_ALLOC(repo);
935

936
	repo->gitdir = git_str_detach(&gitdir);
937
	GIT_ERROR_CHECK_ALLOC(repo->gitdir);
938

939
	if (gitlink.size) {
940
		repo->gitlink = git_str_detach(&gitlink);
941
		GIT_ERROR_CHECK_ALLOC(repo->gitlink);
942
	}
943
	if (commondir.size) {
944
		repo->commondir = git_str_detach(&commondir);
945
		GIT_ERROR_CHECK_ALLOC(repo->commondir);
946
	}
947

948
	if ((error = repo_is_worktree(&is_worktree, repo)) < 0)
949
		goto cleanup;
950
	repo->is_worktree = is_worktree;
951

952 953 954 955 956 957 958 959 960
	/*
	 * We'd like to have the config, but git doesn't particularly
	 * care if it's not there, so we need to deal with that.
	 */

	error = git_repository_config_snapshot(&config, repo);
	if (error < 0 && error != GIT_ENOTFOUND)
		goto cleanup;

961 962 963
	if (config && (error = check_repositoryformatversion(&version, config)) < 0)
		goto cleanup;

964
	if ((error = check_extensions(config, version)) < 0)
965 966
		goto cleanup;

967
	if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) {
968
		repo->is_bare = 1;
969
	} else {
970 971
		if (config &&
		    ((error = load_config_data(repo, config)) < 0 ||
972
		     (error = load_workdir(repo, config, &workdir)) < 0))
973
			goto cleanup;
974
	}
975

976 977 978 979 980
	/*
	 * Ensure that the git directory is owned by the current user.
	 */
	validation_path = repo->is_bare ? repo->gitdir : repo->workdir;

981 982
	if (git_repository__validate_ownership &&
	    (error = validate_ownership(validation_path)) < 0)
983 984
		goto cleanup;

985
cleanup:
986 987 988 989
	git_str_dispose(&gitdir);
	git_str_dispose(&workdir);
	git_str_dispose(&gitlink);
	git_str_dispose(&commondir);
990 991 992 993
	git_config_free(config);

	if (error < 0)
		git_repository_free(repo);
994
	else if (repo_ptr)
995
		*repo_ptr = repo;
996 997

	return error;
998
}
999

1000 1001 1002 1003 1004 1005
int git_repository_open(git_repository **repo_out, const char *path)
{
	return git_repository_open_ext(
		repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL);
}

1006 1007
int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *wt)
{
1008
	git_str path = GIT_STR_INIT;
1009
	git_repository *repo = NULL;
1010 1011
	size_t len;
	int err;
1012

1013 1014
	GIT_ASSERT_ARG(repo_out);
	GIT_ASSERT_ARG(wt);
1015 1016 1017 1018 1019 1020 1021 1022 1023

	*repo_out = NULL;
	len = strlen(wt->gitlink_path);

	if (len <= 4 || strcasecmp(wt->gitlink_path + len - 4, ".git")) {
		err = -1;
		goto out;
	}

1024
	if ((err = git_str_set(&path, wt->gitlink_path, len - 4)) < 0)
1025 1026 1027 1028 1029 1030 1031 1032
		goto out;

	if ((err = git_repository_open(&repo, path.ptr)) < 0)
		goto out;

	*repo_out = repo;

out:
1033
	git_str_dispose(&path);
1034 1035 1036 1037

	return err;
}

1038 1039 1040 1041 1042
int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb)
{
	git_repository *repo;

	repo = repository_alloc();
1043
	GIT_ERROR_CHECK_ALLOC(repo);
1044 1045 1046 1047 1048 1049 1050

	git_repository_set_odb(repo, odb);
	*repo_out = repo;

	return 0;
}

1051
int git_repository_discover(
1052
	git_buf *out,
1053 1054 1055 1056 1057 1058
	const char *start_path,
	int across_fs,
	const char *ceiling_dirs)
{
	uint32_t flags = across_fs ? GIT_REPOSITORY_OPEN_CROSS_FS : 0;

1059
	GIT_ASSERT_ARG(start_path);
1060

1061
	GIT_BUF_WRAP_PRIVATE(out, find_repo, NULL, NULL, NULL, start_path, flags, ceiling_dirs);
1062 1063
}

1064
static int load_config(
1065 1066 1067
	git_config **out,
	git_repository *repo,
	const char *global_config_path,
Sven Strickroth committed
1068
	const char *xdg_config_path,
1069 1070
	const char *system_config_path,
	const char *programdata_path)
1071
{
1072
	int error;
1073
	git_str config_path = GIT_STR_INIT;
1074
	git_config *cfg = NULL;
1075

1076
	GIT_ASSERT_ARG(out);
1077

1078 1079
	if ((error = git_config_new(&cfg)) < 0)
		return error;
1080

1081
	if (repo) {
1082
		if ((error = git_repository__item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0)
1083
			error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, repo, 0);
1084

1085 1086
		if (error && error != GIT_ENOTFOUND)
			goto on_error;
1087

1088
		git_str_dispose(&config_path);
1089
	}
1090

1091 1092
	if (global_config_path != NULL &&
		(error = git_config_add_file_ondisk(
1093
			cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, repo, 0)) < 0 &&
1094 1095
		error != GIT_ENOTFOUND)
		goto on_error;
1096

1097 1098
	if (xdg_config_path != NULL &&
		(error = git_config_add_file_ondisk(
1099
			cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, repo, 0)) < 0 &&
1100 1101
		error != GIT_ENOTFOUND)
		goto on_error;
1102

1103 1104
	if (system_config_path != NULL &&
		(error = git_config_add_file_ondisk(
1105
			cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, repo, 0)) < 0 &&
1106 1107
		error != GIT_ENOTFOUND)
		goto on_error;
1108

1109 1110
	if (programdata_path != NULL &&
		(error = git_config_add_file_ondisk(
1111
			cfg, programdata_path, GIT_CONFIG_LEVEL_PROGRAMDATA, repo, 0)) < 0 &&
1112 1113 1114
		error != GIT_ENOTFOUND)
		goto on_error;

1115
	git_error_clear(); /* clear any lingering ENOTFOUND errors */
1116

1117
	*out = cfg;
1118
	return 0;
1119

1120
on_error:
1121
	git_str_dispose(&config_path);
1122 1123
	git_config_free(cfg);
	*out = NULL;
1124
	return error;
1125 1126
}

1127
static const char *path_unless_empty(git_str *buf)
1128
{
1129
	return git_str_len(buf) > 0 ? git_str_cstr(buf) : NULL;
Russell Belfer committed
1130
}
1131

Russell Belfer committed
1132 1133 1134
int git_repository_config__weakptr(git_config **out, git_repository *repo)
{
	int error = 0;
1135

Russell Belfer committed
1136
	if (repo->_config == NULL) {
1137 1138 1139 1140
		git_str global_buf = GIT_STR_INIT;
		git_str xdg_buf = GIT_STR_INIT;
		git_str system_buf = GIT_STR_INIT;
		git_str programdata_buf = GIT_STR_INIT;
Russell Belfer committed
1141 1142
		git_config *config;

1143 1144 1145 1146
		git_config__find_global(&global_buf);
		git_config__find_xdg(&xdg_buf);
		git_config__find_system(&system_buf);
		git_config__find_programdata(&programdata_buf);
Russell Belfer committed
1147

1148
		/* If there is no global file, open a backend for it anyway */
1149
		if (git_str_len(&global_buf) == 0)
1150 1151
			git_config__global_location(&global_buf);

Russell Belfer committed
1152 1153 1154 1155
		error = load_config(
			&config, repo,
			path_unless_empty(&global_buf),
			path_unless_empty(&xdg_buf),
1156 1157
			path_unless_empty(&system_buf),
			path_unless_empty(&programdata_buf));
Russell Belfer committed
1158 1159 1160
		if (!error) {
			GIT_REFCOUNT_OWN(config, repo);

1161
			if (git_atomic_compare_and_swap(&repo->_config, NULL, config) != NULL) {
Russell Belfer committed
1162 1163 1164 1165
				GIT_REFCOUNT_OWN(config, NULL);
				git_config_free(config);
			}
		}
1166

1167 1168 1169 1170
		git_str_dispose(&global_buf);
		git_str_dispose(&xdg_buf);
		git_str_dispose(&system_buf);
		git_str_dispose(&programdata_buf);
1171
	}
1172

1173
	*out = repo->_config;
Russell Belfer committed
1174
	return error;
1175 1176
}

1177
int git_repository_config(git_config **out, git_repository *repo)
1178
{
1179 1180
	if (git_repository_config__weakptr(out, repo) < 0)
		return -1;
1181

1182 1183
	GIT_REFCOUNT_INC(*out);
	return 0;
1184 1185
}

1186 1187
int git_repository_config_snapshot(git_config **out, git_repository *repo)
{
1188
	int error;
1189 1190
	git_config *weak;

1191 1192
	if ((error = git_repository_config__weakptr(&weak, repo)) < 0)
		return error;
1193 1194 1195 1196

	return git_config_snapshot(out, weak);
}

1197
int git_repository_set_config(git_repository *repo, git_config *config)
1198
{
1199 1200 1201
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(config);

1202
	set_config(repo, config);
1203
	return 0;
1204 1205 1206 1207
}

int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
{
Russell Belfer committed
1208 1209
	int error = 0;

1210 1211
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(out);
1212

1213
	*out = git_atomic_load(repo->_odb);
lhchavez committed
1214
	if (*out == NULL) {
1215
		git_str odb_path = GIT_STR_INIT;
Russell Belfer committed
1216
		git_odb *odb;
1217

1218
		if ((error = git_repository__item_path(&odb_path, repo,
1219 1220
				GIT_REPOSITORY_ITEM_OBJECTS)) < 0 ||
			(error = git_odb_new(&odb)) < 0)
1221
			return error;
1222

1223
		GIT_REFCOUNT_OWN(odb, repo);
1224

1225 1226 1227 1228 1229 1230
		if ((error = git_odb__set_caps(odb, GIT_ODB_CAP_FROM_OWNER)) < 0 ||
			(error = git_odb__add_default_backends(odb, odb_path.ptr, 0, 0)) < 0) {
			git_odb_free(odb);
			return error;
		}

1231
		if (git_atomic_compare_and_swap(&repo->_odb, NULL, odb) != NULL) {
1232 1233
			GIT_REFCOUNT_OWN(odb, NULL);
			git_odb_free(odb);
Russell Belfer committed
1234
		}
1235

1236
		git_str_dispose(&odb_path);
1237
		*out = git_atomic_load(repo->_odb);
1238
	}
1239

Russell Belfer committed
1240
	return error;
1241 1242
}

1243
int git_repository_odb(git_odb **out, git_repository *repo)
1244
{
1245 1246
	if (git_repository_odb__weakptr(out, repo) < 0)
		return -1;
Vicent Marti committed
1247

1248 1249
	GIT_REFCOUNT_INC(*out);
	return 0;
1250
}
1251

1252
int git_repository_set_odb(git_repository *repo, git_odb *odb)
1253
{
1254 1255 1256
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(odb);

1257
	set_odb(repo, odb);
1258
	return 0;
1259 1260
}

1261 1262
int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo)
{
Russell Belfer committed
1263 1264
	int error = 0;

1265 1266
	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(repo);
1267 1268

	if (repo->_refdb == NULL) {
Russell Belfer committed
1269
		git_refdb *refdb;
1270

Russell Belfer committed
1271 1272 1273
		error = git_refdb_open(&refdb, repo);
		if (!error) {
			GIT_REFCOUNT_OWN(refdb, repo);
1274

1275
			if (git_atomic_compare_and_swap(&repo->_refdb, NULL, refdb) != NULL) {
Russell Belfer committed
1276 1277 1278 1279
				GIT_REFCOUNT_OWN(refdb, NULL);
				git_refdb_free(refdb);
			}
		}
1280 1281 1282
	}

	*out = repo->_refdb;
Russell Belfer committed
1283
	return error;
1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294
}

int git_repository_refdb(git_refdb **out, git_repository *repo)
{
	if (git_repository_refdb__weakptr(out, repo) < 0)
		return -1;

	GIT_REFCOUNT_INC(*out);
	return 0;
}

1295
int git_repository_set_refdb(git_repository *repo, git_refdb *refdb)
1296
{
1297 1298 1299
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(refdb);

1300
	set_refdb(repo, refdb);
1301
	return 0;
1302 1303
}

1304 1305
int git_repository_index__weakptr(git_index **out, git_repository *repo)
{
Russell Belfer committed
1306 1307
	int error = 0;

1308 1309
	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(repo);
1310 1311

	if (repo->_index == NULL) {
1312
		git_str index_path = GIT_STR_INIT;
Russell Belfer committed
1313
		git_index *index;
1314

1315
		if ((error = git_str_joinpath(&index_path, repo->gitdir, GIT_INDEX_FILE)) < 0)
1316
			return error;
1317

Russell Belfer committed
1318 1319 1320
		error = git_index_open(&index, index_path.ptr);
		if (!error) {
			GIT_REFCOUNT_OWN(index, repo);
1321

1322
			if (git_atomic_compare_and_swap(&repo->_index, NULL, index) != NULL) {
Russell Belfer committed
1323 1324 1325
				GIT_REFCOUNT_OWN(index, NULL);
				git_index_free(index);
			}
1326

1327 1328
			error = git_index_set_caps(repo->_index,
			                           GIT_INDEX_CAPABILITY_FROM_OWNER);
Russell Belfer committed
1329
		}
1330

1331
		git_str_dispose(&index_path);
1332 1333 1334
	}

	*out = repo->_index;
Russell Belfer committed
1335
	return error;
1336
}
Vicent Marti committed
1337

1338 1339
int git_repository_index(git_index **out, git_repository *repo)
{
1340 1341
	if (git_repository_index__weakptr(out, repo) < 0)
		return -1;
1342

1343 1344
	GIT_REFCOUNT_INC(*out);
	return 0;
1345 1346
}

1347
int git_repository_set_index(git_repository *repo, git_index *index)
1348
{
1349
	GIT_ASSERT_ARG(repo);
1350
	set_index(repo, index);
1351
	return 0;
1352 1353
}

Vicent Marti committed
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
int git_repository_set_namespace(git_repository *repo, const char *namespace)
{
	git__free(repo->namespace);

	if (namespace == NULL) {
		repo->namespace = NULL;
		return 0;
	}

	return (repo->namespace = git__strdup(namespace)) ? 0 : -1;
}

const char *git_repository_get_namespace(git_repository *repo)
{
	return repo->namespace;
}

1371 1372
#ifdef GIT_WIN32
static int reserved_names_add8dot3(git_repository *repo, const char *path)
1373
{
1374 1375
	char *name = git_win32_path_8dot3_name(path);
	const char *def = GIT_DIR_SHORTNAME;
1376
	const char *def_dot_git = DOT_GIT;
1377
	size_t name_len, def_len = CONST_STRLEN(GIT_DIR_SHORTNAME);
1378
	size_t def_dot_git_len = CONST_STRLEN(DOT_GIT);
1379
	git_str *buf;
1380

1381 1382 1383 1384 1385
	if (!name)
		return 0;

	name_len = strlen(name);

1386
	if ((name_len == def_len && memcmp(name, def, def_len) == 0) ||
1387
		(name_len == def_dot_git_len && memcmp(name, def_dot_git, def_dot_git_len) == 0)) {
1388 1389 1390 1391 1392 1393 1394
		git__free(name);
		return 0;
	}

	if ((buf = git_array_alloc(repo->reserved_names)) == NULL)
		return -1;

1395
	git_str_attach(buf, name, name_len);
1396 1397 1398 1399
	return true;
}

bool git_repository__reserved_names(
1400
	git_str **out, size_t *outlen, git_repository *repo, bool include_ntfs)
1401 1402 1403 1404
{
	GIT_UNUSED(include_ntfs);

	if (repo->reserved_names.size == 0) {
1405
		git_str *buf;
1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
		size_t i;

		/* Add the static defaults */
		for (i = 0; i < git_repository__reserved_names_win32_len; i++) {
			if ((buf = git_array_alloc(repo->reserved_names)) == NULL)
				goto on_error;

			buf->ptr = git_repository__reserved_names_win32[i].ptr;
			buf->size = git_repository__reserved_names_win32[i].size;
		}

1417 1418 1419 1420 1421 1422
		/* Try to add any repo-specific reserved names - the gitlink file
		 * within a submodule or the repository (if the repository directory
		 * is beneath the workdir).  These are typically `.git`, but should
		 * be protected in case they are not.  Note, repo and workdir paths
		 * are always prettified to end in `/`, so a prefixcmp is safe.
		 */
1423
		if (!repo->is_bare) {
1424 1425
			int (*prefixcmp)(const char *, const char *);
			int error, ignorecase;
1426

1427 1428
			error = git_repository__configmap_lookup(
				&ignorecase, repo, GIT_CONFIGMAP_IGNORECASE);
1429 1430 1431
			prefixcmp = (error || ignorecase) ? git__prefixcmp_icase :
				git__prefixcmp;

1432 1433
			if (repo->gitlink &&
				reserved_names_add8dot3(repo, repo->gitlink) < 0)
1434 1435
				goto on_error;

1436 1437 1438
			if (repo->gitdir &&
				prefixcmp(repo->gitdir, repo->workdir) == 0 &&
				reserved_names_add8dot3(repo, repo->gitdir) < 0)
1439
				goto on_error;
1440 1441 1442
		}
	}

1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
	*out = repo->reserved_names.ptr;
	*outlen = repo->reserved_names.size;

	return true;

	/* Always give good defaults, even on OOM */
on_error:
	*out = git_repository__reserved_names_win32;
	*outlen = git_repository__reserved_names_win32_len;

	return false;
1454
}
1455 1456
#else
bool git_repository__reserved_names(
1457
	git_str **out, size_t *outlen, git_repository *repo, bool include_ntfs)
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471
{
	GIT_UNUSED(repo);

	if (include_ntfs) {
		*out = git_repository__reserved_names_win32;
		*outlen = git_repository__reserved_names_win32_len;
	} else {
		*out = git_repository__reserved_names_posix;
		*outlen = git_repository__reserved_names_posix_len;
	}

	return true;
}
#endif
1472

1473
static int check_repositoryformatversion(int *version, git_config *config)
1474
{
1475
	int error;
1476

1477
	error = git_config_get_int32(version, config, "core.repositoryformatversion");
1478 1479 1480 1481 1482
	/* git ignores this if the config variable isn't there */
	if (error == GIT_ENOTFOUND)
		return 0;

	if (error < 0)
1483
		return -1;
1484

1485
	if (GIT_REPO_MAX_VERSION < *version) {
1486
		git_error_set(GIT_ERROR_REPOSITORY,
1487 1488
			"unsupported repository version %d; only versions up to %d are supported",
			*version, GIT_REPO_MAX_VERSION);
1489 1490
		return -1;
	}
1491

1492
	return 0;
1493 1494
}

1495 1496 1497 1498 1499 1500
static const char *builtin_extensions[] = {
	"noop"
};

static git_vector user_extensions = GIT_VECTOR_INIT;

1501 1502
static int check_valid_extension(const git_config_entry *entry, void *payload)
{
1503
	git_str cfg = GIT_STR_INIT;
1504 1505 1506 1507 1508
	bool reject;
	const char *extension;
	size_t i;
	int error = 0;

1509 1510
	GIT_UNUSED(payload);

1511
	git_vector_foreach (&user_extensions, i, extension) {
1512
		git_str_clear(&cfg);
1513

1514 1515 1516 1517 1518 1519 1520
		/*
		 * Users can specify that they don't want to support an
		 * extension with a '!' prefix.
		 */
		if ((reject = (extension[0] == '!')) == true)
			extension = &extension[1];

1521
		if ((error = git_str_printf(&cfg, "extensions.%s", extension)) < 0)
1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532
			goto done;

		if (strcmp(entry->name, cfg.ptr) == 0) {
			if (reject)
				goto fail;

			goto done;
		}
	}

	for (i = 0; i < ARRAY_SIZE(builtin_extensions); i++) {
1533
		git_str_clear(&cfg);
1534 1535
		extension = builtin_extensions[i];

1536
		if ((error = git_str_printf(&cfg, "extensions.%s", extension)) < 0)
1537 1538 1539 1540 1541 1542 1543
			goto done;

		if (strcmp(entry->name, cfg.ptr) == 0)
			goto done;
	}

fail:
1544
	git_error_set(GIT_ERROR_REPOSITORY, "unsupported extension name %s", entry->name);
1545 1546 1547
	error = -1;

done:
1548
	git_str_dispose(&cfg);
1549
	return error;
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
}

static int check_extensions(git_config *config, int version)
{
	if (version < 1)
		return 0;

	return git_config_foreach_match(config, "^extensions\\.", check_valid_extension, NULL);
}

1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623
int git_repository__extensions(char ***out, size_t *out_len)
{
	git_vector extensions;
	const char *builtin, *user;
	char *extension;
	size_t i, j;

	if (git_vector_init(&extensions, 8, NULL) < 0)
		return -1;

	for (i = 0; i < ARRAY_SIZE(builtin_extensions); i++) {
		bool match = false;

		builtin = builtin_extensions[i];

		git_vector_foreach (&user_extensions, j, user) {
			if (user[0] == '!' && strcmp(builtin, &user[1]) == 0) {
				match = true;
				break;
			}
		}

		if (match)
			continue;

		if ((extension = git__strdup(builtin)) == NULL ||
		    git_vector_insert(&extensions, extension) < 0)
			return -1;
	}

	git_vector_foreach (&user_extensions, i, user) {
		if (user[0] == '!')
			continue;

		if ((extension = git__strdup(user)) == NULL ||
		    git_vector_insert(&extensions, extension) < 0)
			return -1;
	}

	*out = (char **)git_vector_detach(out_len, NULL, &extensions);
	return 0;
}

int git_repository__set_extensions(const char **extensions, size_t len)
{
	char *extension;
	size_t i;

	git_repository__free_extensions();

	for (i = 0; i < len; i++) {
		if ((extension = git__strdup(extensions[i])) == NULL ||
		    git_vector_insert(&user_extensions, extension) < 0)
			return -1;
	}

	return 0;
}

void git_repository__free_extensions(void)
{
	git_vector_free_deep(&user_extensions);
}

1624
int git_repository_create_head(const char *git_dir, const char *ref_name)
1625
{
1626
	git_str ref_path = GIT_STR_INIT;
1627
	git_filebuf ref = GIT_FILEBUF_INIT;
1628
	const char *fmt;
1629
	int error;
1630

1631
	if ((error = git_str_joinpath(&ref_path, git_dir, GIT_HEAD_FILE)) < 0 ||
1632 1633
	    (error = git_filebuf_open(&ref, ref_path.ptr, 0, GIT_REFS_FILE_MODE)) < 0)
		goto out;
1634

1635
	if (git__prefixcmp(ref_name, GIT_REFS_DIR) == 0)
1636 1637
		fmt = "ref: %s\n";
	else
1638
		fmt = "ref: " GIT_REFS_HEADS_DIR "%s\n";
1639

1640 1641 1642
	if ((error = git_filebuf_printf(&ref, fmt, ref_name)) < 0 ||
	    (error = git_filebuf_commit(&ref)) < 0)
		goto out;
1643

1644
out:
1645
	git_str_dispose(&ref_path);
1646
	git_filebuf_cleanup(&ref);
1647
	return error;
1648 1649
}

1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
static bool is_chmod_supported(const char *file_path)
{
	struct stat st1, st2;

	if (p_stat(file_path, &st1) < 0)
		return false;

	if (p_chmod(file_path, st1.st_mode ^ S_IXUSR) < 0)
		return false;

	if (p_stat(file_path, &st2) < 0)
		return false;

1663
	return (st1.st_mode != st2.st_mode);
1664 1665
}

1666 1667
static bool is_filesystem_case_insensitive(const char *gitdir_path)
{
1668
	git_str path = GIT_STR_INIT;
1669
	int is_insensitive = -1;
1670

1671
	if (!git_str_joinpath(&path, gitdir_path, "CoNfIg"))
1672
		is_insensitive = git_fs_path_exists(git_str_cstr(&path));
1673

1674
	git_str_dispose(&path);
1675
	return is_insensitive;
1676 1677
}

1678 1679 1680 1681 1682
/*
 * Return a configuration object with only the global and system
 * configurations; no repository-level configuration.
 */
static int load_global_config(git_config **config)
1683
{
1684 1685 1686 1687
	git_str global_buf = GIT_STR_INIT;
	git_str xdg_buf = GIT_STR_INIT;
	git_str system_buf = GIT_STR_INIT;
	git_str programdata_buf = GIT_STR_INIT;
1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711
	int error;

	git_config__find_global(&global_buf);
	git_config__find_xdg(&xdg_buf);
	git_config__find_system(&system_buf);
	git_config__find_programdata(&programdata_buf);

	error = load_config(config, NULL,
	                    path_unless_empty(&global_buf),
	                    path_unless_empty(&xdg_buf),
	                    path_unless_empty(&system_buf),
	                    path_unless_empty(&programdata_buf));

	git_str_dispose(&global_buf);
	git_str_dispose(&xdg_buf);
	git_str_dispose(&system_buf);
	git_str_dispose(&programdata_buf);

	return error;
}

static bool are_symlinks_supported(const char *wd_path)
{
	git_config *config = NULL;
1712
	int symlinks = 0;
1713 1714 1715 1716 1717 1718 1719 1720 1721

	/*
	 * To emulate Git for Windows, symlinks on Windows must be explicitly
	 * opted-in.  We examine the system configuration for a core.symlinks
	 * set to true.  If found, we then examine the filesystem to see if
	 * symlinks are _actually_ supported by the current user.  If that is
	 * _not_ set, then we do not test or enable symlink support.
	 */
#ifdef GIT_WIN32
1722 1723 1724
	if (load_global_config(&config) < 0 ||
	    git_config_get_bool(&symlinks, config, "core.symlinks") < 0 ||
	    !symlinks)
1725 1726
		goto done;
#endif
1727

1728
	if (!(symlinks = git_fs_path_supports_symlinks(wd_path)))
1729 1730 1731 1732
		goto done;

done:
	git_config_free(config);
1733
	return symlinks != 0;
1734 1735
}

1736 1737 1738 1739 1740
static int create_empty_file(const char *path, mode_t mode)
{
	int fd;

	if ((fd = p_creat(path, mode)) < 0) {
1741
		git_error_set(GIT_ERROR_OS, "error while creating '%s'", path);
1742 1743 1744 1745
		return -1;
	}

	if (p_close(fd) < 0) {
1746
		git_error_set(GIT_ERROR_OS, "error while closing '%s'", path);
1747 1748 1749 1750 1751 1752
		return -1;
	}

	return 0;
}

1753 1754
static int repo_local_config(
	git_config **out,
1755
	git_str *config_dir,
1756 1757
	git_repository *repo,
	const char *repo_dir)
1758
{
1759
	int error = 0;
1760 1761
	git_config *parent;
	const char *cfg_path;
1762

1763
	if (git_str_joinpath(config_dir, repo_dir, GIT_CONFIG_FILENAME_INREPO) < 0)
1764
		return -1;
1765
	cfg_path = git_str_cstr(config_dir);
1766

1767
	/* make LOCAL config if missing */
1768
	if (!git_fs_path_isfile(cfg_path) &&
1769
		(error = create_empty_file(cfg_path, GIT_CONFIG_FILE_MODE)) < 0)
1770
		return error;
1771

1772 1773 1774 1775 1776 1777 1778 1779 1780
	/* if no repo, just open that file directly */
	if (!repo)
		return git_config_open_ondisk(out, cfg_path);

	/* otherwise, open parent config and get that level */
	if ((error = git_repository_config__weakptr(&parent, repo)) < 0)
		return error;

	if (git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL) < 0) {
1781
		git_error_clear();
1782 1783

		if (!(error = git_config_add_file_ondisk(
1784
				parent, cfg_path, GIT_CONFIG_LEVEL_LOCAL, repo, false)))
1785
			error = git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL);
1786
	}
1787

1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812
	git_config_free(parent);

	return error;
}

static int repo_init_fs_configs(
	git_config *cfg,
	const char *cfg_path,
	const char *repo_dir,
	const char *work_dir,
	bool update_ignorecase)
{
	int error = 0;

	if (!work_dir)
		work_dir = repo_dir;

	if ((error = git_config_set_bool(
			cfg, "core.filemode", is_chmod_supported(cfg_path))) < 0)
		return error;

	if (!are_symlinks_supported(work_dir)) {
		if ((error = git_config_set_bool(cfg, "core.symlinks", false)) < 0)
			return error;
	} else if (git_config_delete_entry(cfg, "core.symlinks") < 0)
1813
		git_error_clear();
1814

1815 1816 1817 1818 1819
	if (update_ignorecase) {
		if (is_filesystem_case_insensitive(repo_dir)) {
			if ((error = git_config_set_bool(cfg, "core.ignorecase", true)) < 0)
				return error;
		} else if (git_config_delete_entry(cfg, "core.ignorecase") < 0)
1820
			git_error_clear();
1821
	}
1822

1823
#ifdef GIT_USE_ICONV
1824 1825
	if ((error = git_config_set_bool(
			cfg, "core.precomposeunicode",
1826
			git_fs_path_does_decompose_unicode(work_dir))) < 0)
1827
		return error;
1828
	/* on non-iconv platforms, don't even set core.precomposeunicode */
1829 1830
#endif

1831 1832
	return 0;
}
1833

1834 1835 1836 1837 1838 1839 1840
static int repo_init_config(
	const char *repo_dir,
	const char *work_dir,
	uint32_t flags,
	uint32_t mode)
{
	int error = 0;
1841
	git_str cfg_path = GIT_STR_INIT, worktree_path = GIT_STR_INIT;
1842 1843 1844
	git_config *config = NULL;
	bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
	bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
1845
	int version = 0;
1846 1847 1848 1849

	if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0)
		goto cleanup;

1850 1851 1852
	if (is_reinit && (error = check_repositoryformatversion(&version, config)) < 0)
		goto cleanup;

1853
	if ((error = check_extensions(config, version)) < 0)
1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865
		goto cleanup;

#define SET_REPO_CONFIG(TYPE, NAME, VAL) do { \
	if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \
		goto cleanup; } while (0)

	SET_REPO_CONFIG(bool, "core.bare", is_bare);
	SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION);

	if ((error = repo_init_fs_configs(
			config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0)
		goto cleanup;
1866

1867 1868
	if (!is_bare) {
		SET_REPO_CONFIG(bool, "core.logallrefupdates", true);
1869

1870
		if (!(flags & GIT_REPOSITORY_INIT__NATURAL_WD)) {
1871
			if ((error = git_str_sets(&worktree_path, work_dir)) < 0)
1872 1873 1874
				goto cleanup;

			if ((flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK))
1875
				if ((error = git_fs_path_make_relative(&worktree_path, repo_dir)) < 0)
1876 1877 1878 1879
					goto cleanup;

			SET_REPO_CONFIG(string, "core.worktree", worktree_path.ptr);
		} else if (is_reinit) {
Ben Straub committed
1880
			if (git_config_delete_entry(config, "core.worktree") < 0)
1881
				git_error_clear();
1882 1883 1884
		}
	}

1885
	if (mode == GIT_REPOSITORY_INIT_SHARED_GROUP) {
1886 1887
		SET_REPO_CONFIG(int32, "core.sharedrepository", 1);
		SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true);
1888
	}
1889
	else if (mode == GIT_REPOSITORY_INIT_SHARED_ALL) {
1890 1891 1892
		SET_REPO_CONFIG(int32, "core.sharedrepository", 2);
		SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true);
	}
1893

1894
cleanup:
1895 1896
	git_str_dispose(&cfg_path);
	git_str_dispose(&worktree_path);
1897
	git_config_free(config);
1898

1899
	return error;
1900
}
1901

1902
static int repo_reinit_submodule_fs(git_submodule *sm, const char *n, void *p)
1903
{
1904 1905
	git_repository *smrepo = NULL;
	GIT_UNUSED(n); GIT_UNUSED(p);
1906

1907
	if (git_submodule_open(&smrepo, sm) < 0 ||
1908
		git_repository_reinit_filesystem(smrepo, true) < 0)
1909
		git_error_clear();
1910
	git_repository_free(smrepo);
1911

1912 1913
	return 0;
}
1914

1915
int git_repository_reinit_filesystem(git_repository *repo, int recurse)
1916 1917
{
	int error = 0;
1918
	git_str path = GIT_STR_INIT;
1919 1920
	git_config *config = NULL;
	const char *repo_dir = git_repository_path(repo);
1921

1922 1923 1924
	if (!(error = repo_local_config(&config, &path, repo, repo_dir)))
		error = repo_init_fs_configs(
			config, path.ptr, repo_dir, git_repository_workdir(repo), true);
1925

1926
	git_config_free(config);
1927
	git_str_dispose(&path);
1928

1929
	git_repository__configmap_lookup_cache_clear(repo);
1930

1931
	if (!repo->is_bare && recurse)
1932
		(void)git_submodule_foreach(repo, repo_reinit_submodule_fs, NULL);
1933

1934 1935 1936
	return error;
}

1937
static int repo_write_template(
1938 1939 1940 1941
	const char *git_dir,
	bool allow_overwrite,
	const char *file,
	mode_t mode,
1942
	bool hidden,
1943
	const char *content)
1944
{
1945
	git_str path = GIT_STR_INIT;
1946
	int fd, error = 0, flags;
1947

1948
	if (git_str_joinpath(&path, git_dir, file) < 0)
1949 1950
		return -1;

1951 1952 1953 1954 1955
	if (allow_overwrite)
		flags = O_WRONLY | O_CREAT | O_TRUNC;
	else
		flags = O_WRONLY | O_CREAT | O_EXCL;

1956
	fd = p_open(git_str_cstr(&path), flags, mode);
1957

1958 1959
	if (fd >= 0) {
		error = p_write(fd, content, strlen(content));
1960

1961 1962 1963 1964
		p_close(fd);
	}
	else if (errno != EEXIST)
		error = fd;
1965

1966 1967
#ifdef GIT_WIN32
	if (!error && hidden) {
1968
		if (git_win32__set_hidden(path.ptr, true) < 0)
1969 1970 1971 1972 1973 1974
			error = -1;
	}
#else
	GIT_UNUSED(hidden);
#endif

1975
	git_str_dispose(&path);
1976 1977

	if (error)
1978
		git_error_set(GIT_ERROR_OS,
1979
			"failed to initialize repository with template '%s'", file);
1980 1981

	return error;
1982 1983
}

1984
static int repo_write_gitlink(
1985
	const char *in_dir, const char *to_repo, bool use_relative_path)
1986
{
1987
	int error;
1988 1989
	git_str buf = GIT_STR_INIT;
	git_str path_to_repo = GIT_STR_INIT;
1990 1991
	struct stat st;

1992 1993
	git_fs_path_dirname_r(&buf, to_repo);
	git_fs_path_to_dir(&buf);
1994
	if (git_str_oom(&buf))
1995
		return -1;
1996

1997 1998 1999 2000 2001 2002 2003 2004
	/* don't write gitlink to natural workdir */
	if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 &&
		strcmp(in_dir, buf.ptr) == 0)
	{
		error = GIT_PASSTHROUGH;
		goto cleanup;
	}

2005
	if ((error = git_str_joinpath(&buf, in_dir, DOT_GIT)) < 0)
2006 2007 2008
		goto cleanup;

	if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) {
2009
		git_error_set(GIT_ERROR_REPOSITORY,
2010
			"cannot overwrite gitlink file into path '%s'", in_dir);
2011 2012 2013 2014
		error = GIT_EEXISTS;
		goto cleanup;
	}

2015
	git_str_clear(&buf);
2016

2017
	error = git_str_sets(&path_to_repo, to_repo);
2018 2019

	if (!error && use_relative_path)
2020
		error = git_fs_path_make_relative(&path_to_repo, in_dir);
2021 2022

	if (!error)
2023
		error = git_str_join(&buf, ' ', GIT_FILE_CONTENT_PREFIX, path_to_repo.ptr);
2024 2025

	if (!error)
2026
		error = repo_write_template(in_dir, true, DOT_GIT, 0666, true, buf.ptr);
2027 2028

cleanup:
2029 2030
	git_str_dispose(&buf);
	git_str_dispose(&path_to_repo);
2031 2032 2033
	return error;
}

2034 2035 2036
static mode_t pick_dir_mode(git_repository_init_options *opts)
{
	if (opts->mode == GIT_REPOSITORY_INIT_SHARED_UMASK)
2037
		return 0777;
2038 2039 2040 2041 2042 2043 2044
	if (opts->mode == GIT_REPOSITORY_INIT_SHARED_GROUP)
		return (0775 | S_ISGID);
	if (opts->mode == GIT_REPOSITORY_INIT_SHARED_ALL)
		return (0777 | S_ISGID);
	return opts->mode;
}

2045 2046 2047 2048 2049 2050 2051
#include "repo_template.h"

static int repo_init_structure(
	const char *repo_dir,
	const char *work_dir,
	git_repository_init_options *opts)
{
2052
	int error = 0;
2053
	repo_template_item *tpl;
2054 2055 2056
	bool external_tpl =
		((opts->flags & GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) != 0);
	mode_t dmode = pick_dir_mode(opts);
2057
	bool chmod = opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK;
2058 2059

	/* Hide the ".git" directory */
2060
#ifdef GIT_WIN32
2061
	if ((opts->flags & GIT_REPOSITORY_INIT__HAS_DOTGIT) != 0) {
2062
		if (git_win32__set_hidden(repo_dir, true) < 0) {
2063
			git_error_set(GIT_ERROR_OS,
2064
				"failed to mark Git repository folder as hidden");
2065 2066
			return -1;
		}
2067
	}
2068 2069 2070 2071 2072 2073
#endif

	/* Create the .git gitlink if appropriate */
	if ((opts->flags & GIT_REPOSITORY_INIT_BARE) == 0 &&
		(opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD) == 0)
	{
2074
		if (repo_write_gitlink(work_dir, repo_dir, opts->flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK) < 0)
2075
			return -1;
2076
	}
2077

2078 2079
	/* Copy external template if requested */
	if (external_tpl) {
Linquize committed
2080 2081 2082
		git_config *cfg = NULL;
		const char *tdir = NULL;
		bool default_template = false;
2083
		git_str template_buf = GIT_STR_INIT;
2084

2085 2086
		if (opts->template_path)
			tdir = opts->template_path;
Linquize committed
2087
		else if ((error = git_config_open_default(&cfg)) >= 0) {
2088
			if (!git_config__get_path(&template_buf, cfg, "init.templatedir"))
2089
				tdir = template_buf.ptr;
2090
			git_error_clear();
Linquize committed
2091 2092 2093
		}

		if (!tdir) {
2094
			if (!(error = git_sysdir_find_template_dir(&template_buf)))
2095
				tdir = template_buf.ptr;
Linquize committed
2096
			default_template = true;
2097
		}
2098

2099 2100 2101 2102 2103 2104 2105
		/*
		 * If tdir was the empty string, treat it like tdir was a path to an
		 * empty directory (so, don't do any copying). This is the behavior
		 * that git(1) exhibits, although it doesn't seem to be officially
		 * documented.
		 */
		if (tdir && git__strcmp(tdir, "") != 0) {
2106 2107 2108
			uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS |
				GIT_CPDIR_SIMPLE_TO_MODE |
				GIT_CPDIR_COPY_DOTFILES;
2109 2110 2111
			if (opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK)
					cpflags |= GIT_CPDIR_CHMOD_DIRS;
			error = git_futils_cp_r(tdir, repo_dir, cpflags, dmode);
2112
		}
2113

2114
		git_str_dispose(&template_buf);
Linquize committed
2115
		git_config_free(cfg);
2116

2117 2118 2119 2120 2121
		/* If tdir does not exist, then do not error out. This matches the
		 * behaviour of git(1), which just prints a warning and continues.
		 * TODO: issue warning when warning API is available.
		 * `git` prints to stderr: 'warning: templates not found in /path/to/tdir'
		 */
2122
		if (error < 0) {
2123
			if (!default_template && error != GIT_ENOTFOUND)
2124 2125 2126
				return error;

			/* if template was default, ignore error and use internal */
2127
			git_error_clear();
2128
			external_tpl = false;
2129
			error = 0;
2130 2131 2132 2133 2134 2135 2136 2137
		}
	}

	/* Copy internal template
	 * - always ensure existence of dirs
	 * - only create files if no external template was specified
	 */
	for (tpl = repo_template; !error && tpl->path; ++tpl) {
2138
		if (!tpl->content) {
2139 2140 2141 2142
			uint32_t mkdir_flags = GIT_MKDIR_PATH;
			if (chmod)
				mkdir_flags |= GIT_MKDIR_CHMOD;

2143 2144
			error = git_futils_mkdir_relative(
				tpl->path, repo_dir, dmode, mkdir_flags, NULL);
2145
		}
2146
		else if (!external_tpl) {
2147 2148 2149 2150 2151
			const char *content = tpl->content;

			if (opts->description && strcmp(tpl->path, GIT_DESC_FILE) == 0)
				content = opts->description;

2152 2153
			error = repo_write_template(
				repo_dir, false, tpl->path, tpl->mode, false, content);
2154
		}
2155 2156
	}

2157
	return error;
2158 2159
}

2160
static int mkdir_parent(git_str *buf, uint32_t mode, bool skip2)
2161
{
2162 2163 2164
	/* When making parent directories during repository initialization
	 * don't try to set gid or grant world write access
	 */
2165
	return git_futils_mkdir(
2166
		buf->ptr, mode & ~(S_ISGID | 0002),
2167 2168 2169 2170
		GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR |
		(skip2 ? GIT_MKDIR_SKIP_LAST2 : GIT_MKDIR_SKIP_LAST));
}

2171
static int repo_init_directories(
2172 2173
	git_str *repo_path,
	git_str *wd_path,
2174 2175
	const char *given_repo,
	git_repository_init_options *opts)
2176
{
2177
	int error = 0;
2178
	bool is_bare, add_dotgit, has_dotgit, natural_wd;
2179
	mode_t dirmode;
2180

2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200
	/* There are three possible rules for what we are allowed to create:
	 * - MKPATH means anything we need
	 * - MKDIR means just the .git directory and its parent and the workdir
	 * - Neither means only the .git directory can be created
	 *
	 * There are 5 "segments" of path that we might need to deal with:
	 * 1. The .git directory
	 * 2. The parent of the .git directory
	 * 3. Everything above the parent of the .git directory
	 * 4. The working directory (often the same as #2)
	 * 5. Everything above the working directory (often the same as #3)
	 *
	 * For all directories created, we start with the init_mode value for
	 * permissions and then strip off bits in some cases:
	 *
	 * For MKPATH, we create #3 (and #5) paths without S_ISGID or S_IWOTH
	 * For MKPATH and MKDIR, we create #2 (and #4) without S_ISGID
	 * For all rules, we create #1 using the untouched init_mode
	 */

2201
	/* set up repo path */
2202

2203 2204
	is_bare = ((opts->flags & GIT_REPOSITORY_INIT_BARE) != 0);

2205 2206
	add_dotgit =
		(opts->flags & GIT_REPOSITORY_INIT_NO_DOTGIT_DIR) == 0 &&
2207
		!is_bare &&
2208 2209
		git__suffixcmp(given_repo, "/" DOT_GIT) != 0 &&
		git__suffixcmp(given_repo, "/" GIT_DIR) != 0;
2210

2211
	if (git_str_joinpath(repo_path, given_repo, add_dotgit ? GIT_DIR : "") < 0)
2212
		return -1;
2213

2214 2215 2216 2217 2218 2219
	has_dotgit = (git__suffixcmp(repo_path->ptr, "/" GIT_DIR) == 0);
	if (has_dotgit)
		opts->flags |= GIT_REPOSITORY_INIT__HAS_DOTGIT;

	/* set up workdir path */

2220
	if (!is_bare) {
2221
		if (opts->workdir_path) {
2222
			if (git_fs_path_join_unrooted(
2223 2224
					wd_path, opts->workdir_path, repo_path->ptr, NULL) < 0)
				return -1;
2225
		} else if (has_dotgit) {
2226
			if (git_fs_path_dirname_r(wd_path, repo_path->ptr) < 0)
2227 2228
				return -1;
		} else {
2229
			git_error_set(GIT_ERROR_REPOSITORY, "cannot pick working directory"
2230 2231 2232
				" for non-bare repository that isn't a '.git' directory");
			return -1;
		}
2233

2234
		if (git_fs_path_to_dir(wd_path) < 0)
2235 2236
			return -1;
	} else {
2237
		git_str_clear(wd_path);
2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249
	}

	natural_wd =
		has_dotgit &&
		wd_path->size > 0 &&
		wd_path->size + strlen(GIT_DIR) == repo_path->size &&
		memcmp(repo_path->ptr, wd_path->ptr, wd_path->size) == 0;
	if (natural_wd)
		opts->flags |= GIT_REPOSITORY_INIT__NATURAL_WD;

	/* create directories as needed / requested */

2250
	dirmode = pick_dir_mode(opts);
2251

2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269
	if ((opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) {
		/* create path #5 */
		if (wd_path->size > 0 &&
			(error = mkdir_parent(wd_path, dirmode, false)) < 0)
			return error;

		/* create path #3 (if not the same as #5) */
		if (!natural_wd &&
			(error = mkdir_parent(repo_path, dirmode, has_dotgit)) < 0)
			return error;
	}

	if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 ||
		(opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0)
	{
		/* create path #4 */
		if (wd_path->size > 0 &&
			(error = git_futils_mkdir(
2270
				wd_path->ptr, dirmode & ~S_ISGID,
2271 2272 2273 2274 2275 2276
				GIT_MKDIR_VERIFY_DIR)) < 0)
			return error;

		/* create path #2 (if not the same as #4) */
		if (!natural_wd &&
			(error = git_futils_mkdir(
2277
				repo_path->ptr, dirmode & ~S_ISGID,
2278 2279
				GIT_MKDIR_VERIFY_DIR | GIT_MKDIR_SKIP_LAST)) < 0)
			return error;
2280 2281
	}

2282 2283 2284 2285
	if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 ||
		(opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0 ||
		has_dotgit)
	{
2286
		/* create path #1 */
2287
		error = git_futils_mkdir(repo_path->ptr, dirmode,
2288
			GIT_MKDIR_VERIFY_DIR | ((dirmode & S_ISGID) ? GIT_MKDIR_CHMOD : 0));
2289
	}
2290

2291 2292 2293
	/* prettify both directories now that they are created */

	if (!error) {
2294
		error = git_fs_path_prettify_dir(repo_path, repo_path->ptr, NULL);
2295 2296

		if (!error && wd_path->size > 0)
2297
			error = git_fs_path_prettify_dir(wd_path, wd_path->ptr, NULL);
2298 2299 2300 2301 2302
	}

	return error;
}

2303 2304 2305
static int repo_init_head(const char *repo_dir, const char *given)
{
	git_config *cfg = NULL;
2306
	git_str head_path = GIT_STR_INIT, cfg_branch = GIT_STR_INIT;
2307 2308 2309
	const char *initial_head = NULL;
	int error;

2310
	if ((error = git_str_joinpath(&head_path, repo_dir, GIT_HEAD_FILE)) < 0)
2311 2312 2313 2314 2315 2316
		goto out;

	/*
	 * A template may have set a HEAD; use that unless it's been
	 * overridden by the caller's given initial head setting.
	 */
2317
	if (git_fs_path_exists(head_path.ptr) && !given)
2318 2319 2320 2321 2322
		goto out;

	if (given) {
		initial_head = given;
	} else if ((error = git_config_open_default(&cfg)) >= 0 &&
2323
	           (error = git_config__get_string_buf(&cfg_branch, cfg, "init.defaultbranch")) >= 0 &&
2324
	           *cfg_branch.ptr) {
2325 2326 2327 2328 2329 2330 2331 2332 2333 2334
		initial_head = cfg_branch.ptr;
	}

	if (!initial_head)
		initial_head = GIT_BRANCH_DEFAULT;

	error = git_repository_create_head(repo_dir, initial_head);

out:
	git_config_free(cfg);
2335 2336
	git_str_dispose(&head_path);
	git_str_dispose(&cfg_branch);
2337 2338 2339 2340

	return error;
}

2341 2342 2343 2344 2345
static int repo_init_create_origin(git_repository *repo, const char *url)
{
	int error;
	git_remote *remote;

Ben Straub committed
2346
	if (!(error = git_remote_create(&remote, repo, GIT_REMOTE_ORIGIN, url))) {
2347 2348 2349 2350 2351 2352 2353 2354 2355
		git_remote_free(remote);
	}

	return error;
}

int git_repository_init(
	git_repository **repo_out, const char *path, unsigned is_bare)
{
2356
	git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
2357 2358 2359 2360 2361 2362 2363 2364 2365

	opts.flags = GIT_REPOSITORY_INIT_MKPATH; /* don't love this default */
	if (is_bare)
		opts.flags |= GIT_REPOSITORY_INIT_BARE;

	return git_repository_init_ext(repo_out, path, &opts);
}

int git_repository_init_ext(
2366
	git_repository **out,
2367 2368 2369
	const char *given_repo,
	git_repository_init_options *opts)
{
2370 2371
	git_str repo_path = GIT_STR_INIT, wd_path = GIT_STR_INIT,
		common_path = GIT_STR_INIT;
2372
	const char *wd;
2373
	bool is_valid;
2374
	int error;
2375

2376 2377 2378
	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(given_repo);
	GIT_ASSERT_ARG(opts);
2379

2380
	GIT_ERROR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options");
2381

2382 2383
	if ((error = repo_init_directories(&repo_path, &wd_path, given_repo, opts)) < 0)
		goto out;
2384

2385
	wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_str_cstr(&wd_path);
2386

2387 2388 2389 2390
	if ((error = is_valid_repository_path(&is_valid, &repo_path, &common_path)) < 0)
		goto out;

	if (is_valid) {
2391
		if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) {
2392
			git_error_set(GIT_ERROR_REPOSITORY,
2393
				"attempt to reinitialize '%s'", given_repo);
2394
			error = GIT_EEXISTS;
2395
			goto out;
2396 2397 2398 2399
		}

		opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT;

2400 2401
		if ((error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode)) < 0)
			goto out;
2402 2403

		/* TODO: reinitialize the templates */
2404 2405 2406
	} else {
		if ((error = repo_init_structure(repo_path.ptr, wd, opts)) < 0 ||
		    (error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode)) < 0 ||
2407
		    (error = repo_init_head(repo_path.ptr, opts->initial_head)) < 0)
2408
			goto out;
2409 2410
	}

2411 2412
	if ((error = git_repository_open(out, repo_path.ptr)) < 0)
		goto out;
2413

2414 2415 2416
	if (opts->origin_url &&
	    (error = repo_init_create_origin(*out, opts->origin_url)) < 0)
		goto out;
2417

2418
out:
2419 2420 2421
	git_str_dispose(&common_path);
	git_str_dispose(&repo_path);
	git_str_dispose(&wd_path);
2422 2423

	return error;
2424
}
2425

2426
int git_repository_head_detached(git_repository *repo)
2427 2428
{
	git_reference *ref;
2429
	git_odb *odb = NULL;
2430
	int exists;
2431

2432 2433
	if (git_repository_odb__weakptr(&odb, repo) < 0)
		return -1;
2434

2435 2436
	if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0)
		return -1;
2437

2438
	if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
2439
		git_reference_free(ref);
2440
		return 0;
2441
	}
2442

2443
	exists = git_odb_exists(odb, git_reference_target(ref));
2444 2445

	git_reference_free(ref);
2446
	return exists;
2447 2448
}

2449 2450
int git_repository_head_detached_for_worktree(git_repository *repo, const char *name)
{
2451 2452
	git_reference *ref = NULL;
	int error;
2453

2454 2455
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(name);
2456

2457 2458
	if ((error = git_repository_head_for_worktree(&ref, repo, name)) < 0)
		goto out;
2459

2460
	error = (git_reference_type(ref) != GIT_REFERENCE_SYMBOLIC);
2461 2462
out:
	git_reference_free(ref);
2463

2464
	return error;
2465 2466
}

2467
int git_repository_head(git_reference **head_out, git_repository *repo)
2468
{
2469
	git_reference *head;
2470 2471
	int error;

2472
	GIT_ASSERT_ARG(head_out);
2473

2474 2475 2476
	if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
		return error;

2477
	if (git_reference_type(head) == GIT_REFERENCE_DIRECT) {
2478 2479 2480 2481
		*head_out = head;
		return 0;
	}

2482
	error = git_reference_lookup_resolved(head_out, repo, git_reference_symbolic_target(head), -1);
2483
	git_reference_free(head);
2484

2485
	return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error;
2486 2487
}

2488 2489
int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name)
{
2490 2491
	git_repository *worktree_repo = NULL;
	git_worktree *worktree = NULL;
2492 2493
	git_reference *head = NULL;
	int error;
2494

2495 2496 2497
	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(name);
2498 2499 2500

	*out = NULL;

2501 2502 2503
	if ((error = git_worktree_lookup(&worktree, repo, name)) < 0 ||
	    (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0 ||
	    (error = git_reference_lookup(&head, worktree_repo, GIT_HEAD_FILE)) < 0)
2504 2505
		goto out;

2506
	if (git_reference_type(head) != GIT_REFERENCE_DIRECT) {
2507 2508 2509 2510 2511
		if ((error = git_reference_lookup_resolved(out, worktree_repo, git_reference_symbolic_target(head), -1)) < 0)
			goto out;
	} else {
		*out = head;
		head = NULL;
2512 2513 2514
	}

out:
2515 2516 2517
	git_reference_free(head);
	git_worktree_free(worktree);
	git_repository_free(worktree_repo);
2518
	return error;
2519 2520
}

2521 2522 2523 2524 2525 2526 2527 2528 2529 2530
int git_repository_foreach_worktree(git_repository *repo,
				    git_repository_foreach_worktree_cb cb,
				    void *payload)
{
	git_strarray worktrees = {0};
	git_repository *worktree_repo = NULL;
	git_worktree *worktree = NULL;
	int error;
	size_t i;

2531 2532 2533 2534 2535 2536
	/* apply operation to repository supplied when commondir is empty, implying there's
	 * no linked worktrees to iterate, which can occur when using custom odb/refdb
	 */
	if (!repo->commondir)
		return cb(repo, payload);

2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571
	if ((error = git_repository_open(&worktree_repo, repo->commondir)) < 0 ||
	    (error = cb(worktree_repo, payload) != 0))
		goto out;

	git_repository_free(worktree_repo);
	worktree_repo = NULL;

	if ((error = git_worktree_list(&worktrees, repo)) < 0)
		goto out;

	for (i = 0; i < worktrees.count; i++) {
		git_repository_free(worktree_repo);
		worktree_repo = NULL;
		git_worktree_free(worktree);
		worktree = NULL;

		if ((error = git_worktree_lookup(&worktree, repo, worktrees.strings[i]) < 0) ||
		    (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0) {
			if (error != GIT_ENOTFOUND)
				goto out;
			error = 0;
			continue;
		}

		if ((error = cb(worktree_repo, payload)) != 0)
			goto out;
	}

out:
	git_strarray_dispose(&worktrees);
	git_repository_free(worktree_repo);
	git_worktree_free(worktree);
	return error;
}

2572
int git_repository_head_unborn(git_repository *repo)
2573
{
2574
	git_reference *ref = NULL;
2575 2576 2577
	int error;

	error = git_repository_head(&ref, repo);
2578
	git_reference_free(ref);
2579

2580
	if (error == GIT_EUNBORNBRANCH) {
2581
		git_error_clear();
2582
		return 1;
2583
	}
2584

2585 2586 2587 2588
	if (error < 0)
		return -1;

	return 0;
2589
}
2590

2591 2592
static int repo_contains_no_reference(git_repository *repo)
{
2593 2594 2595
	git_reference_iterator *iter;
	const char *refname;
	int error;
2596

2597 2598
	if ((error = git_reference_iterator_new(&iter, repo)) < 0)
		return error;
2599

2600 2601 2602 2603
	error = git_reference_next_name(&refname, iter);
	git_reference_iterator_free(iter);

	if (error == GIT_ITEROVER)
2604
		return 1;
2605

2606
	return error;
2607
}
2608

2609
int git_repository_initialbranch(git_str *out, git_repository *repo)
2610 2611 2612 2613
{
	git_config *config;
	git_config_entry *entry = NULL;
	const char *branch;
2614
	int valid, error;
2615 2616 2617 2618

	if ((error = git_repository_config__weakptr(&config, repo)) < 0)
		return error;

2619 2620
	if ((error = git_config_get_entry(&entry, config, "init.defaultbranch")) == 0 &&
		*entry->value) {
2621 2622
		branch = entry->value;
	}
2623
	else if (!error || error == GIT_ENOTFOUND) {
2624 2625 2626 2627 2628 2629
		branch = GIT_BRANCH_DEFAULT;
	}
	else {
		goto done;
	}

2630 2631
	if ((error = git_str_puts(out, GIT_REFS_HEADS_DIR)) < 0 ||
	    (error = git_str_puts(out, branch)) < 0 ||
2632
	    (error = git_reference_name_is_valid(&valid, out->ptr)) < 0)
2633 2634
	    goto done;

2635
	if (!valid) {
2636
		git_error_set(GIT_ERROR_INVALID, "the value of init.defaultBranch is not a valid branch name");
2637 2638 2639 2640 2641 2642 2643 2644
		error = -1;
	}

done:
	git_config_entry_free(entry);
	return error;
}

2645 2646 2647
int git_repository_is_empty(git_repository *repo)
{
	git_reference *head = NULL;
2648
	git_str initialbranch = GIT_STR_INIT;
2649
	int result = 0;
2650

2651 2652 2653
	if ((result = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0 ||
	    (result = git_repository_initialbranch(&initialbranch, repo)) < 0)
		goto done;
2654

2655 2656 2657
	result = (git_reference_type(head) == GIT_REFERENCE_SYMBOLIC &&
	          strcmp(git_reference_symbolic_target(head), initialbranch.ptr) == 0 &&
	          repo_contains_no_reference(repo));
2658

2659
done:
2660
	git_reference_free(head);
2661
	git_str_dispose(&initialbranch);
2662

2663
	return result;
2664 2665
}

2666
static const char *resolved_parent_path(const git_repository *repo, git_repository_item_t item, git_repository_item_t fallback)
2667 2668 2669
{
	const char *parent;

2670
	switch (item) {
2671 2672 2673 2674 2675 2676 2677 2678 2679 2680
		case GIT_REPOSITORY_ITEM_GITDIR:
			parent = git_repository_path(repo);
			break;
		case GIT_REPOSITORY_ITEM_WORKDIR:
			parent = git_repository_workdir(repo);
			break;
		case GIT_REPOSITORY_ITEM_COMMONDIR:
			parent = git_repository_commondir(repo);
			break;
		default:
2681
			git_error_set(GIT_ERROR_INVALID, "invalid item directory");
2682
			return NULL;
2683
	}
2684 2685 2686 2687 2688
	if (!parent && fallback != GIT_REPOSITORY_ITEM__LAST)
		return resolved_parent_path(repo, fallback, GIT_REPOSITORY_ITEM__LAST);

	return parent;
}
2689

2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701
int git_repository_item_path(
	git_buf *out,
	const git_repository *repo,
	git_repository_item_t item)
{
	GIT_BUF_WRAP_PRIVATE(out, git_repository__item_path, repo, item);
}

int git_repository__item_path(
	git_str *out,
	const git_repository *repo,
	git_repository_item_t item)
2702 2703
{
	const char *parent = resolved_parent_path(repo, items[item].parent, items[item].fallback);
2704
	if (parent == NULL) {
2705
		git_error_set(GIT_ERROR_INVALID, "path cannot exist in repository");
2706
		return GIT_ENOTFOUND;
2707 2708
	}

2709
	if (git_str_sets(out, parent) < 0)
2710 2711 2712
		return -1;

	if (items[item].name) {
2713
		if (git_str_joinpath(out, parent, items[item].name) < 0)
2714 2715 2716 2717
			return -1;
	}

	if (items[item].directory) {
2718
		if (git_fs_path_to_dir(out) < 0)
2719 2720 2721 2722 2723 2724
			return -1;
	}

	return 0;
}

2725
const char *git_repository_path(const git_repository *repo)
2726
{
2727
	GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL);
2728
	return repo->gitdir;
2729
}
2730

2731
const char *git_repository_workdir(const git_repository *repo)
2732
{
2733
	GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL);
2734

2735 2736
	if (repo->is_bare)
		return NULL;
2737

2738 2739
	return repo->workdir;
}
2740

2741
int git_repository_workdir_path(
2742
	git_str *out, git_repository *repo, const char *path)
2743 2744 2745 2746 2747 2748 2749 2750
{
	int error;

	if (!repo->workdir) {
		git_error_set(GIT_ERROR_REPOSITORY, "repository has no working directory");
		return GIT_EBAREREPO;
	}

2751
	if (!(error = git_str_joinpath(out, repo->workdir, path)))
2752
		error = git_path_validate_str_length(repo, out);
2753 2754 2755 2756

	return error;
}

2757
const char *git_repository_commondir(const git_repository *repo)
2758
{
2759
	GIT_ASSERT_ARG_WITH_RETVAL(repo, NULL);
2760 2761 2762
	return repo->commondir;
}

2763 2764
int git_repository_set_workdir(
	git_repository *repo, const char *workdir, int update_gitlink)
2765
{
2766
	int error = 0;
2767
	git_str path = GIT_STR_INIT;
2768

2769 2770
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(workdir);
2771

2772
	if (git_fs_path_prettify_dir(&path, workdir, NULL) < 0)
2773
		return -1;
2774

2775 2776
	if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0)
		return 0;
2777

2778 2779 2780 2781 2782 2783
	if (update_gitlink) {
		git_config *config;

		if (git_repository_config__weakptr(&config, repo) < 0)
			return -1;

2784
		error = repo_write_gitlink(path.ptr, git_repository_path(repo), false);
2785 2786 2787

		/* passthrough error means gitlink is unnecessary */
		if (error == GIT_PASSTHROUGH)
Ben Straub committed
2788
			error = git_config_delete_entry(config, "core.worktree");
2789 2790 2791 2792 2793 2794 2795 2796 2797 2798
		else if (!error)
			error = git_config_set_string(config, "core.worktree", path.ptr);

		if (!error)
			error = git_config_set_bool(config, "core.bare", false);
	}

	if (!error) {
		char *old_workdir = repo->workdir;

2799
		repo->workdir = git_str_detach(&path);
2800 2801 2802 2803 2804 2805
		repo->is_bare = 0;

		git__free(old_workdir);
	}

	return error;
2806
}
2807

2808
int git_repository_is_bare(const git_repository *repo)
2809
{
2810
	GIT_ASSERT_ARG(repo);
2811 2812
	return repo->is_bare;
}
2813

2814
int git_repository_is_worktree(const git_repository *repo)
2815
{
2816
	GIT_ASSERT_ARG(repo);
2817 2818 2819
	return repo->is_worktree;
}

2820 2821 2822 2823 2824
int git_repository_set_bare(git_repository *repo)
{
	int error;
	git_config *config;

2825
	GIT_ASSERT_ARG(repo);
2826 2827 2828 2829

	if (repo->is_bare)
		return 0;

2830 2831 2832
	if ((error = git_repository_config__weakptr(&config, repo)) < 0)
		return error;

2833
	if ((error = git_config_set_bool(config, "core.bare", true)) < 0)
2834
		return error;
2835

2836 2837
	if ((error = git_config__update_entry(config, "core.worktree", NULL, true, true)) < 0)
		return error;
2838 2839 2840 2841 2842

	git__free(repo->workdir);
	repo->workdir = NULL;
	repo->is_bare = 1;

2843
	return 0;
2844 2845
}

2846 2847
int git_repository_head_tree(git_tree **tree, git_repository *repo)
{
2848 2849 2850
	git_reference *head;
	git_object *obj;
	int error;
2851

2852 2853
	if ((error = git_repository_head(&head, repo)) < 0)
		return error;
2854

2855
	if ((error = git_reference_peel(&obj, head, GIT_OBJECT_TREE)) < 0)
2856
		goto cleanup;
2857 2858

	*tree = (git_tree *)obj;
2859 2860 2861 2862

cleanup:
	git_reference_free(head);
	return error;
2863
}
2864

2865 2866 2867
int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head)
{
	git_filebuf file = GIT_FILEBUF_INIT;
2868
	git_str file_path = GIT_STR_INIT;
2869 2870 2871 2872 2873
	char orig_head_str[GIT_OID_HEXSZ];
	int error = 0;

	git_oid_fmt(orig_head_str, orig_head);

2874
	if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_ORIG_HEAD_FILE)) == 0 &&
2875
		(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) == 0 &&
2876 2877 2878 2879 2880 2881
		(error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0)
		error = git_filebuf_commit(&file);

	if (error < 0)
		git_filebuf_cleanup(&file);

2882
	git_str_dispose(&file_path);
2883 2884 2885 2886

	return error;
}

2887
static int git_repository__message(git_str *out, git_repository *repo)
2888
{
2889
	git_str path = GIT_STR_INIT;
Vicent Marti committed
2890 2891
	struct stat st;
	int error;
2892

2893
	if (git_str_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0)
Vicent Marti committed
2894
		return -1;
2895

2896
	if ((error = p_stat(git_str_cstr(&path), &st)) < 0) {
2897 2898
		if (errno == ENOENT)
			error = GIT_ENOTFOUND;
2899
		git_error_set(GIT_ERROR_OS, "could not access message file");
2900
	} else {
2901
		error = git_futils_readbuffer(out, git_str_cstr(&path));
Vicent Marti committed
2902
	}
2903

2904
	git_str_dispose(&path);
2905 2906

	return error;
2907 2908
}

2909 2910 2911 2912 2913
int git_repository_message(git_buf *out, git_repository *repo)
{
	GIT_BUF_WRAP_PRIVATE(out, git_repository__message, repo);
}

2914 2915
int git_repository_message_remove(git_repository *repo)
{
2916
	git_str path = GIT_STR_INIT;
Vicent Marti committed
2917
	int error;
2918

2919
	if (git_str_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0)
Vicent Marti committed
2920
		return -1;
2921

2922 2923
	error = p_unlink(git_str_cstr(&path));
	git_str_dispose(&path);
2924 2925 2926

	return error;
}
2927 2928

int git_repository_hashfile(
Linquize committed
2929 2930 2931
	git_oid *out,
	git_repository *repo,
	const char *path,
2932
	git_object_t type,
Linquize committed
2933
	const char *as_path)
2934 2935
{
	int error;
2936
	git_filter_list *fl = NULL;
2937
	git_file fd = -1;
2938
	uint64_t len;
2939
	git_str full_path = GIT_STR_INIT;
2940
	const char *workdir = git_repository_workdir(repo);
2941

2942 2943 2944 2945
	 /* as_path can be NULL */
	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(path);
	GIT_ASSERT_ARG(repo);
2946

2947
	if ((error = git_fs_path_join_unrooted(&full_path, path, workdir, NULL)) < 0 ||
2948
	    (error = git_path_validate_str_length(repo, &full_path)) < 0)
2949 2950
		return error;

2951 2952 2953 2954 2955 2956 2957 2958 2959 2960
	/*
	 * NULL as_path means that we should derive it from the
	 * given path.
	 */
	if (!as_path) {
		if (workdir && !git__prefixcmp(full_path.ptr, workdir))
			as_path = full_path.ptr + strlen(workdir);
		else
			as_path = "";
	}
2961 2962 2963

	/* passing empty string for "as_path" indicated --no-filters */
	if (strlen(as_path) > 0) {
Russell Belfer committed
2964
		error = git_filter_list_load(
2965
			&fl, repo, NULL, as_path,
2966
			GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT);
2967

2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979
		if (error < 0)
			return error;
	}

	/* at this point, error is a count of the number of loaded filters */

	fd = git_futils_open_ro(full_path.ptr);
	if (fd < 0) {
		error = fd;
		goto cleanup;
	}

2980
	if ((error = git_futils_filesize(&len, fd)) < 0)
2981 2982 2983
		goto cleanup;

	if (!git__is_sizet(len)) {
2984
		git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems");
2985 2986 2987 2988
		error = -1;
		goto cleanup;
	}

2989
	error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, fl);
2990 2991

cleanup:
2992 2993
	if (fd >= 0)
		p_close(fd);
2994
	git_filter_list_free(fl);
2995
	git_str_dispose(&full_path);
2996 2997 2998 2999

	return error;
}

3000
static int checkout_message(git_str *out, git_reference *old, const char *new)
3001
{
3002
	git_str_puts(out, "checkout: moving from ");
3003

3004
	if (git_reference_type(old) == GIT_REFERENCE_SYMBOLIC)
3005
		git_str_puts(out, git_reference__shorthand(git_reference_symbolic_target(old)));
3006
	else
3007
		git_str_puts(out, git_oid_tostr_s(git_reference_target(old)));
3008

3009
	git_str_puts(out, " to ");
3010

3011 3012 3013
	if (git_reference__is_branch(new) ||
		git_reference__is_tag(new) ||
		git_reference__is_remote(new))
3014
		git_str_puts(out, git_reference__shorthand(new));
3015
	else
3016
		git_str_puts(out, new);
3017

3018
	if (git_str_oom(out))
3019 3020 3021
		return -1;

	return 0;
3022 3023
}

3024 3025 3026
static int detach(git_repository *repo, const git_oid *id, const char *new)
{
	int error;
3027
	git_str log_message = GIT_STR_INIT;
3028 3029 3030
	git_object *object = NULL, *peeled = NULL;
	git_reference *new_head = NULL, *current = NULL;

3031 3032
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(id);
3033 3034 3035 3036

	if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
		return error;

3037
	if ((error = git_object_lookup(&object, repo, id, GIT_OBJECT_ANY)) < 0)
3038 3039
		goto cleanup;

3040
	if ((error = git_object_peel(&peeled, object, GIT_OBJECT_COMMIT)) < 0)
3041 3042 3043 3044 3045 3046 3047 3048
		goto cleanup;

	if (new == NULL)
		new = git_oid_tostr_s(git_object_id(peeled));

	if ((error = checkout_message(&log_message, current, new)) < 0)
		goto cleanup;

3049
	error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_str_cstr(&log_message));
3050 3051

cleanup:
3052
	git_str_dispose(&log_message);
3053 3054 3055 3056 3057 3058 3059
	git_object_free(object);
	git_object_free(peeled);
	git_reference_free(current);
	git_reference_free(new_head);
	return error;
}

3060
int git_repository_set_head(
3061 3062
	git_repository *repo,
	const char *refname)
3063
{
3064
	git_reference *ref = NULL, *current = NULL, *new_head = NULL;
3065
	git_str log_message = GIT_STR_INIT;
3066 3067
	int error;

3068 3069
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(refname);
3070

3071 3072 3073 3074 3075 3076
	if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
		return error;

	if ((error = checkout_message(&log_message, current, refname)) < 0)
		goto cleanup;

3077 3078
	error = git_reference_lookup(&ref, repo, refname);
	if (error < 0 && error != GIT_ENOTFOUND)
3079
		goto cleanup;
3080

3081
	if (ref && current->type == GIT_REFERENCE_SYMBOLIC && git__strcmp(current->target.symbolic, ref->name) &&
3082
	    git_reference_is_branch(ref) && git_branch_is_checked_out(ref)) {
3083
		git_error_set(GIT_ERROR_REPOSITORY, "cannot set HEAD to reference '%s' as it is the current HEAD "
3084
			"of a linked repository.", git_reference_name(ref));
3085 3086 3087 3088
		error = -1;
		goto cleanup;
	}

3089
	if (!error) {
3090 3091
		if (git_reference_is_branch(ref)) {
			error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE,
3092
					git_reference_name(ref), true, git_str_cstr(&log_message));
3093
		} else {
3094
			error = detach(repo, git_reference_target(ref),
3095
				git_reference_is_tag(ref) || git_reference_is_remote(ref) ? refname : NULL);
3096
		}
3097
	} else if (git_reference__is_branch(refname)) {
3098
		error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname,
3099
				true, git_str_cstr(&log_message));
3100
	}
3101

3102
cleanup:
3103
	git_str_dispose(&log_message);
3104
	git_reference_free(current);
3105 3106 3107 3108 3109
	git_reference_free(ref);
	git_reference_free(new_head);
	return error;
}

3110
int git_repository_set_head_detached(
3111
	git_repository *repo,
Dimitris Apostolou committed
3112
	const git_oid *committish)
3113
{
Dimitris Apostolou committed
3114
	return detach(repo, committish, NULL);
3115 3116 3117 3118
}

int git_repository_set_head_detached_from_annotated(
	git_repository *repo,
Dimitris Apostolou committed
3119
	const git_annotated_commit *committish)
3120
{
3121
	GIT_ASSERT_ARG(repo);
Dimitris Apostolou committed
3122
	GIT_ASSERT_ARG(committish);
3123

Dimitris Apostolou committed
3124
	return detach(repo, git_annotated_commit_id(committish), committish->description);
3125 3126
}

3127
int git_repository_detach_head(git_repository *repo)
3128
{
3129
	git_reference *old_head = NULL,	*new_head = NULL, *current = NULL;
3130
	git_object *object = NULL;
3131
	git_str log_message = GIT_STR_INIT;
3132
	int error;
3133

3134
	GIT_ASSERT_ARG(repo);
3135

3136
	if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
3137
		return error;
3138

3139 3140 3141
	if ((error = git_repository_head(&old_head, repo)) < 0)
		goto cleanup;

3142
	if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJECT_COMMIT)) < 0)
3143 3144
		goto cleanup;

3145 3146 3147
	if ((error = checkout_message(&log_message, current, git_oid_tostr_s(git_object_id(object)))) < 0)
		goto cleanup;

3148
	error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head),
3149
			1, git_str_cstr(&log_message));
3150 3151

cleanup:
3152
	git_str_dispose(&log_message);
3153 3154 3155
	git_object_free(object);
	git_reference_free(old_head);
	git_reference_free(new_head);
3156
	git_reference_free(current);
3157 3158
	return error;
}
Edward Thomson committed
3159

3160 3161 3162 3163
/**
 * Loosely ported from git.git
 * https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh#L198-289
 */
Edward Thomson committed
3164 3165
int git_repository_state(git_repository *repo)
{
3166
	git_str repo_path = GIT_STR_INIT;
Edward Thomson committed
3167 3168
	int state = GIT_REPOSITORY_STATE_NONE;

3169
	GIT_ASSERT_ARG(repo);
Edward Thomson committed
3170

3171
	if (git_str_puts(&repo_path, repo->gitdir) < 0)
Edward Thomson committed
3172 3173
		return -1;

3174
	if (git_fs_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE))
3175
		state = GIT_REPOSITORY_STATE_REBASE_INTERACTIVE;
3176
	else if (git_fs_path_contains_dir(&repo_path, GIT_REBASE_MERGE_DIR))
3177
		state = GIT_REPOSITORY_STATE_REBASE_MERGE;
3178
	else if (git_fs_path_contains_file(&repo_path, GIT_REBASE_APPLY_REBASING_FILE))
3179
		state = GIT_REPOSITORY_STATE_REBASE;
3180
	else if (git_fs_path_contains_file(&repo_path, GIT_REBASE_APPLY_APPLYING_FILE))
3181
		state = GIT_REPOSITORY_STATE_APPLY_MAILBOX;
3182
	else if (git_fs_path_contains_dir(&repo_path, GIT_REBASE_APPLY_DIR))
3183
		state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE;
3184
	else if (git_fs_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE))
Edward Thomson committed
3185
		state = GIT_REPOSITORY_STATE_MERGE;
3186
	else if (git_fs_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE)) {
Edward Thomson committed
3187
		state = GIT_REPOSITORY_STATE_REVERT;
3188
		if (git_fs_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) {
3189 3190
			state = GIT_REPOSITORY_STATE_REVERT_SEQUENCE;
		}
3191
	} else if (git_fs_path_contains_file(&repo_path, GIT_CHERRYPICK_HEAD_FILE)) {
3192
		state = GIT_REPOSITORY_STATE_CHERRYPICK;
3193
		if (git_fs_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) {
3194 3195
			state = GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE;
		}
3196
	} else if (git_fs_path_contains_file(&repo_path, GIT_BISECT_LOG_FILE))
3197
		state = GIT_REPOSITORY_STATE_BISECT;
Edward Thomson committed
3198

3199
	git_str_dispose(&repo_path);
Edward Thomson committed
3200 3201
	return state;
}
Ben Straub committed
3202

3203 3204
int git_repository__cleanup_files(
	git_repository *repo, const char *files[], size_t files_len)
3205
{
3206
	git_str buf = GIT_STR_INIT;
3207
	size_t i;
3208
	int error;
3209

3210 3211
	for (error = 0, i = 0; !error && i < files_len; ++i) {
		const char *path;
3212

3213
		if (git_str_joinpath(&buf, repo->gitdir, files[i]) < 0)
3214
			return -1;
3215

3216
		path = git_str_cstr(&buf);
3217

3218
		if (git_fs_path_isfile(path)) {
3219
			error = p_unlink(path);
3220
		} else if (git_fs_path_isdir(path)) {
3221 3222 3223
			error = git_futils_rmdir_r(path, NULL,
				GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS);
		}
3224

3225
		git_str_clear(&buf);
3226
	}
3227

3228
	git_str_dispose(&buf);
3229 3230 3231 3232 3233 3234 3235 3236
	return error;
}

static const char *state_files[] = {
	GIT_MERGE_HEAD_FILE,
	GIT_MERGE_MODE_FILE,
	GIT_MERGE_MSG_FILE,
	GIT_REVERT_HEAD_FILE,
3237
	GIT_CHERRYPICK_HEAD_FILE,
3238 3239 3240
	GIT_BISECT_LOG_FILE,
	GIT_REBASE_MERGE_DIR,
	GIT_REBASE_APPLY_DIR,
3241
	GIT_SEQUENCER_DIR,
3242 3243 3244 3245
};

int git_repository_state_cleanup(git_repository *repo)
{
3246
	GIT_ASSERT_ARG(repo);
3247 3248 3249 3250

	return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
}

Ben Straub committed
3251 3252
int git_repository_is_shallow(git_repository *repo)
{
3253
	git_str path = GIT_STR_INIT;
Ben Straub committed
3254
	struct stat st;
Ben Straub committed
3255
	int error;
Ben Straub committed
3256

3257
	if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0)
3258 3259
		return error;

3260
	error = git_fs_path_lstat(path.ptr, &st);
3261
	git_str_dispose(&path);
Ben Straub committed
3262

3263
	if (error == GIT_ENOTFOUND) {
3264
		git_error_clear();
Ben Straub committed
3265
		return 0;
3266 3267
	}

Ben Straub committed
3268 3269 3270
	if (error < 0)
		return error;
	return st.st_size == 0 ? 0 : 1;
Ben Straub committed
3271
}
3272

3273
int git_repository_init_options_init(
3274
	git_repository_init_options *opts, unsigned int version)
3275
{
3276 3277 3278 3279
	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
		opts, version, git_repository_init_options,
		GIT_REPOSITORY_INIT_OPTIONS_INIT);
	return 0;
3280
}
3281

3282
#ifndef GIT_DEPRECATE_HARD
3283 3284 3285 3286 3287
int git_repository_init_init_options(
	git_repository_init_options *opts, unsigned int version)
{
	return git_repository_init_options_init(opts, version);
}
3288
#endif
3289

3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303
int git_repository_ident(const char **name, const char **email, const git_repository *repo)
{
	*name = repo->ident_name;
	*email = repo->ident_email;

	return 0;
}

int git_repository_set_ident(git_repository *repo, const char *name, const char *email)
{
	char *tmp_name = NULL, *tmp_email = NULL;

	if (name) {
		tmp_name = git__strdup(name);
3304
		GIT_ERROR_CHECK_ALLOC(tmp_name);
3305 3306 3307 3308
	}

	if (email) {
		tmp_email = git__strdup(email);
3309
		GIT_ERROR_CHECK_ALLOC(tmp_email);
3310 3311
	}

3312 3313
	tmp_name = git_atomic_swap(repo->ident_name, tmp_name);
	tmp_email = git_atomic_swap(repo->ident_email, tmp_email);
3314 3315 3316 3317 3318 3319

	git__free(tmp_name);
	git__free(tmp_email);

	return 0;
}
3320 3321 3322

int git_repository_submodule_cache_all(git_repository *repo)
{
3323
	GIT_ASSERT_ARG(repo);
3324
	return git_submodule_cache_init(&repo->submodule_cache, repo);
3325 3326 3327 3328
}

int git_repository_submodule_cache_clear(git_repository *repo)
{
3329
	int error = 0;
3330 3331
	GIT_ASSERT_ARG(repo);

3332 3333
	error = git_submodule_cache_free(repo->submodule_cache);
	repo->submodule_cache = NULL;
lhchavez committed
3334
	return error;
3335
}