]> git.proxmox.com Git - libgit2.git/blame - src/repository.c
Merge pull request #3303 from libgit2/cmn/index-add-submodule
[libgit2.git] / src / repository.c
CommitLineData
3315782c 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
3315782c 3 *
bb742ede
VM
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
3315782c 6 */
7784bcbb 7#include <ctype.h>
3315782c 8
44908fe7 9#include "git2/object.h"
d00d5464 10#include "git2/refdb.h"
1384b688 11#include "git2/sys/repository.h"
d12299fe 12
3315782c
VM
13#include "common.h"
14#include "repository.h"
15#include "commit.h"
16#include "tag.h"
237da401 17#include "blob.h"
6fd195d7 18#include "fileops.h"
83634d38 19#include "sysdir.h"
114f5a6c
RB
20#include "filebuf.h"
21#include "index.h"
b22d1479 22#include "config.h"
9282e921 23#include "refs.h"
47bfa0be
RB
24#include "filter.h"
25#include "odb.h"
096d9e94 26#include "remote.h"
632d8b23 27#include "merge.h"
114f5a6c 28#include "diff_driver.h"
62d38a1d 29#include "annotated_commit.h"
9282e921 30
c2c81615
PK
31#ifdef GIT_WIN32
32# include "win32/w32_util.h"
33#endif
34
16c73d38
CMN
35static int check_repositoryformatversion(git_config *config);
36
7784bcbb 37#define GIT_FILE_CONTENT_PREFIX "gitdir:"
6a01b6bd 38
28990938 39#define GIT_BRANCH_MASTER "master"
40
29e948de 41#define GIT_REPO_VERSION 0
691aa968 42
4196dd8e
ET
43git_buf git_repository__reserved_names_win32[] = {
44 { DOT_GIT, 0, CONST_STRLEN(DOT_GIT) },
45 { GIT_DIR_SHORTNAME, 0, CONST_STRLEN(GIT_DIR_SHORTNAME) }
46};
47size_t git_repository__reserved_names_win32_len = 2;
48
49git_buf git_repository__reserved_names_posix[] = {
50 { DOT_GIT, 0, CONST_STRLEN(DOT_GIT) },
51};
52size_t git_repository__reserved_names_posix_len = 1;
a64119e3 53
e976b56d 54static void set_odb(git_repository *repo, git_odb *odb)
9462c471 55{
e976b56d
RB
56 if (odb) {
57 GIT_REFCOUNT_OWN(odb, repo);
58 GIT_REFCOUNT_INC(odb);
59 }
60
61 if ((odb = git__swap(repo->_odb, odb)) != NULL) {
62 GIT_REFCOUNT_OWN(odb, NULL);
63 git_odb_free(odb);
eb2f3b47 64 }
9462c471 65}
691aa968 66
e976b56d 67static void set_refdb(git_repository *repo, git_refdb *refdb)
d00d5464 68{
e976b56d
RB
69 if (refdb) {
70 GIT_REFCOUNT_OWN(refdb, repo);
71 GIT_REFCOUNT_INC(refdb);
72 }
73
74 if ((refdb = git__swap(repo->_refdb, refdb)) != NULL) {
75 GIT_REFCOUNT_OWN(refdb, NULL);
76 git_refdb_free(refdb);
d00d5464
ET
77 }
78}
79
e976b56d 80static void set_config(git_repository *repo, git_config *config)
9462c471 81{
e976b56d
RB
82 if (config) {
83 GIT_REFCOUNT_OWN(config, repo);
84 GIT_REFCOUNT_INC(config);
85 }
86
87 if ((config = git__swap(repo->_config, config)) != NULL) {
88 GIT_REFCOUNT_OWN(config, NULL);
89 git_config_free(config);
eb2f3b47 90 }
e976b56d
RB
91
92 git_repository__cvar_cache_clear(repo);
691aa968
VM
93}
94
e976b56d 95static void set_index(git_repository *repo, git_index *index)
6fd195d7 96{
e976b56d
RB
97 if (index) {
98 GIT_REFCOUNT_OWN(index, repo);
99 GIT_REFCOUNT_INC(index);
100 }
101
102 if ((index = git__swap(repo->_index, index)) != NULL) {
103 GIT_REFCOUNT_OWN(index, NULL);
104 git_index_free(index);
9462c471 105 }
e0011be3
VM
106}
107
879458e7 108void git_repository__cleanup(git_repository *repo)
e0011be3 109{
879458e7 110 assert(repo);
6fd195d7 111
879458e7 112 git_cache_clear(&repo->objects);
73b51450 113 git_attr_cache_flush(repo);
6fd195d7 114
e976b56d
RB
115 set_config(repo, NULL);
116 set_index(repo, NULL);
117 set_odb(repo, NULL);
118 set_refdb(repo, NULL);
879458e7
VM
119}
120
121void git_repository_free(git_repository *repo)
122{
4196dd8e
ET
123 size_t i;
124
879458e7
VM
125 if (repo == NULL)
126 return;
127
128 git_repository__cleanup(repo);
129
130 git_cache_free(&repo->objects);
3eadfecd 131
114f5a6c 132 git_diff_driver_registry_free(repo->diff_drivers);
3eadfecd 133 repo->diff_drivers = NULL;
9462c471 134
4196dd8e
ET
135 for (i = 0; i < repo->reserved_names.size; i++)
136 git_buf_free(git_array_get(repo->reserved_names, i));
78db0239 137 git_array_clear(repo->reserved_names);
4196dd8e 138
78db0239 139 git__free(repo->path_gitlink);
53607868
RB
140 git__free(repo->path_repository);
141 git__free(repo->workdir);
bade5194 142 git__free(repo->namespace);
659cf202
CMN
143 git__free(repo->ident_name);
144 git__free(repo->ident_email);
53607868 145
6de9b2ee 146 git__memzero(repo, sizeof(*repo));
9462c471 147 git__free(repo);
6fd195d7
VM
148}
149
9462c471
VM
150/*
151 * Git repository open methods
152 *
153 * Open a repository object from its path
154 */
cb8a7961 155static bool valid_repository_path(git_buf *repository_path)
5ad739e8 156{
97769280 157 /* Check OBJECTS_DIR first, since it will generate the longest path name */
1a481123 158 if (git_path_contains_dir(repository_path, GIT_OBJECTS_DIR) == false)
cb8a7961 159 return false;
5ad739e8 160
97769280 161 /* Ensure HEAD file exists */
1a481123 162 if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false)
cb8a7961 163 return false;
5ad739e8 164
1a481123 165 if (git_path_contains_dir(repository_path, GIT_REFS_DIR) == false)
cb8a7961 166 return false;
5ad739e8 167
cb8a7961 168 return true;
5ad739e8
VM
169}
170
51d00446 171static git_repository *repository_alloc(void)
3315782c 172{
3e9e6cda 173 git_repository *repo = git__calloc(1, sizeof(git_repository));
3315782c 174
4196dd8e
ET
175 if (repo == NULL ||
176 git_cache_init(&repo->objects) < 0)
177 goto on_error;
178
179 git_array_init_to_size(repo->reserved_names, 4);
180 if (!repo->reserved_names.ptr)
181 goto on_error;
3315782c 182
f2c25d18
VM
183 /* set all the entries in the cvar cache to `unset` */
184 git_repository__cvar_cache_clear(repo);
185
6fd195d7 186 return repo;
4196dd8e
ET
187
188on_error:
189 if (repo)
190 git_cache_free(&repo->objects);
191
192 git__free(repo);
193 return NULL;
6fd195d7
VM
194}
195
7cc3c920
JW
196int git_repository_new(git_repository **out)
197{
770aca94
ET
198 git_repository *repo;
199
200 *out = repo = repository_alloc();
201 GITERR_CHECK_ALLOC(repo);
202
203 repo->is_bare = 1;
204
7cc3c920
JW
205 return 0;
206}
207
29c4cb09 208static int load_config_data(git_repository *repo, const git_config *config)
ec3c7a16 209{
cb8a7961 210 int is_bare;
ec3c7a16 211
d3e9c4a5 212 /* Try to figure out if it's bare, default to non-bare if it's not set */
29e948de 213 if (git_config_get_bool(&is_bare, config, "core.bare") < 0)
d3e9c4a5
CMN
214 repo->is_bare = 0;
215 else
216 repo->is_bare = is_bare;
c94785a9 217
cb8a7961 218 return 0;
9462c471 219}
ec3c7a16 220
29c4cb09 221static int load_workdir(git_repository *repo, git_config *config, git_buf *parent_path)
9462c471 222{
7784bcbb 223 int error;
9a97f49e 224 git_config_entry *ce;
9f77b3f6 225 git_buf worktree = GIT_BUF_INIT;
ec3c7a16 226
97769280 227 if (repo->is_bare)
cb8a7961 228 return 0;
ec3c7a16 229
9f77b3f6
RB
230 if ((error = git_config__lookup_entry(
231 &ce, config, "core.worktree", false)) < 0)
232 return error;
ec3c7a16 233
9f77b3f6
RB
234 if (ce && ce->value) {
235 if ((error = git_path_prettify_dir(
236 &worktree, ce->value, repo->path_repository)) < 0)
9a97f49e 237 goto cleanup;
9f77b3f6
RB
238
239 repo->workdir = git_buf_detach(&worktree);
5f4a61ae 240 }
9f77b3f6
RB
241 else if (parent_path && git_path_isdir(parent_path->ptr))
242 repo->workdir = git_buf_detach(parent_path);
7784bcbb 243 else {
9f77b3f6 244 if (git_path_dirname_r(&worktree, repo->path_repository) < 0 ||
9a97f49e
CMN
245 git_path_to_dir(&worktree) < 0) {
246 error = -1;
247 goto cleanup;
248 }
9f77b3f6
RB
249
250 repo->workdir = git_buf_detach(&worktree);
7784bcbb
RB
251 }
252
253 GITERR_CHECK_ALLOC(repo->workdir);
9a97f49e
CMN
254cleanup:
255 git_config_entry_free(ce);
256 return error;
ec3c7a16
VM
257}
258
7784bcbb
RB
259/*
260 * This function returns furthest offset into path where a ceiling dir
261 * is found, so we can stop processing the path at that point.
262 *
263 * Note: converting this to use git_bufs instead of GIT_PATH_MAX buffers on
264 * the stack could remove directories name limits, but at the cost of doing
265 * repeated malloc/frees inside the loop below, so let's not do it now.
266 */
267static int find_ceiling_dir_offset(
268 const char *path,
269 const char *ceiling_directories)
270{
271 char buf[GIT_PATH_MAX + 1];
272 char buf2[GIT_PATH_MAX + 1];
273 const char *ceil, *sep;
44ef8b1b 274 size_t len, max_len = 0, min_len;
7784bcbb
RB
275
276 assert(path);
277
44ef8b1b 278 min_len = (size_t)(git_path_root(path) + 1);
7784bcbb
RB
279
280 if (ceiling_directories == NULL || min_len == 0)
44ef8b1b 281 return (int)min_len;
7784bcbb
RB
282
283 for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) {
284 for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);
285 len = sep - ceil;
286
44ef8b1b 287 if (len == 0 || len >= sizeof(buf) || git_path_root(ceil) == -1)
7784bcbb
RB
288 continue;
289
290 strncpy(buf, ceil, len);
291 buf[len] = '\0';
292
293 if (p_realpath(buf, buf2) == NULL)
294 continue;
295
296 len = strlen(buf2);
297 if (len > 0 && buf2[len-1] == '/')
298 buf[--len] = '\0';
299
300 if (!strncmp(path, buf2, len) &&
3fe046cf 301 (path[len] == '/' || !path[len]) &&
7784bcbb
RB
302 len > max_len)
303 {
304 max_len = len;
305 }
306 }
307
44ef8b1b 308 return (int)(max_len <= min_len ? min_len : max_len);
7784bcbb
RB
309}
310
311/*
312 * Read the contents of `file_path` and set `path_out` to the repo dir that
313 * it points to. Before calling, set `path_out` to the base directory that
314 * should be used if the contents of `file_path` are a relative path.
315 */
316static int read_gitfile(git_buf *path_out, const char *file_path)
317{
318 int error = 0;
319 git_buf file = GIT_BUF_INIT;
320 size_t prefix_len = strlen(GIT_FILE_CONTENT_PREFIX);
321
322 assert(path_out && file_path);
323
324 if (git_futils_readbuffer(&file, file_path) < 0)
325 return -1;
326
327 git_buf_rtrim(&file);
6b415f62
RB
328 /* apparently on Windows, some people use backslashes in paths */
329 git_path_mkposix(file.ptr);
7784bcbb 330
662880ca
RB
331 if (git_buf_len(&file) <= prefix_len ||
332 memcmp(git_buf_cstr(&file), GIT_FILE_CONTENT_PREFIX, prefix_len) != 0)
7784bcbb 333 {
6b415f62
RB
334 giterr_set(GITERR_REPOSITORY,
335 "The `.git` file at '%s' is malformed", file_path);
7784bcbb
RB
336 error = -1;
337 }
338 else if ((error = git_path_dirname_r(path_out, file_path)) >= 0) {
662880ca 339 const char *gitlink = git_buf_cstr(&file) + prefix_len;
0f49200c 340 while (*gitlink && git__isspace(*gitlink)) gitlink++;
6b415f62 341
662880ca
RB
342 error = git_path_prettify_dir(
343 path_out, gitlink, git_buf_cstr(path_out));
7784bcbb
RB
344 }
345
346 git_buf_free(&file);
347 return error;
348}
349
350static int find_repo(
351 git_buf *repo_path,
352 git_buf *parent_path,
4196dd8e 353 git_buf *link_path,
7784bcbb
RB
354 const char *start_path,
355 uint32_t flags,
356 const char *ceiling_dirs)
691aa968 357{
7784bcbb
RB
358 int error;
359 git_buf path = GIT_BUF_INIT;
360 struct stat st;
361 dev_t initial_device = 0;
3fe046cf 362 bool try_with_dot_git = ((flags & GIT_REPOSITORY_OPEN_BARE) != 0);
7784bcbb
RB
363 int ceiling_offset;
364
365 git_buf_free(repo_path);
366
3fe046cf 367 if ((error = git_path_prettify(&path, start_path, NULL)) < 0)
7784bcbb
RB
368 return error;
369
370 ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs);
371
3fe046cf
RB
372 if (!try_with_dot_git &&
373 (error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0)
7784bcbb
RB
374 return error;
375
fa6420f7 376 while (!error && !git_buf_len(repo_path)) {
7784bcbb
RB
377 if (p_stat(path.ptr, &st) == 0) {
378 /* check that we have not crossed device boundaries */
379 if (initial_device == 0)
380 initial_device = st.st_dev;
381 else if (st.st_dev != initial_device &&
382 (flags & GIT_REPOSITORY_OPEN_CROSS_FS) == 0)
383 break;
384
385 if (S_ISDIR(st.st_mode)) {
386 if (valid_repository_path(&path)) {
387 git_path_to_dir(&path);
388 git_buf_set(repo_path, path.ptr, path.size);
389 break;
390 }
391 }
392 else if (S_ISREG(st.st_mode)) {
393 git_buf repo_link = GIT_BUF_INIT;
394
395 if (!(error = read_gitfile(&repo_link, path.ptr))) {
4196dd8e 396 if (valid_repository_path(&repo_link)) {
7784bcbb 397 git_buf_swap(repo_path, &repo_link);
146f5c75 398
4196dd8e
ET
399 if (link_path)
400 error = git_buf_put(link_path,
401 path.ptr, path.size);
402 }
403
146f5c75 404 git_buf_free(&repo_link);
7784bcbb
RB
405 break;
406 }
407 git_buf_free(&repo_link);
408 }
409 }
410
411 /* move up one directory level */
412 if (git_path_dirname_r(&path, path.ptr) < 0) {
413 error = -1;
414 break;
415 }
416
417 if (try_with_dot_git) {
418 /* if we tried original dir with and without .git AND either hit
419 * directory ceiling or NO_SEARCH was requested, then be done.
420 */
421 if (path.ptr[ceiling_offset] == '\0' ||
422 (flags & GIT_REPOSITORY_OPEN_NO_SEARCH) != 0)
423 break;
424 /* otherwise look first for .git item */
425 error = git_buf_joinpath(&path, path.ptr, DOT_GIT);
426 }
427 try_with_dot_git = !try_with_dot_git;
428 }
429
3fe046cf 430 if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
fa6420f7 431 if (!git_buf_len(repo_path))
7784bcbb
RB
432 git_buf_clear(parent_path);
433 else {
434 git_path_dirname_r(parent_path, path.ptr);
435 git_path_to_dir(parent_path);
436 }
437 if (git_buf_oom(parent_path))
438 return -1;
439 }
440
441 git_buf_free(&path);
442
fa6420f7 443 if (!git_buf_len(repo_path) && !error) {
cb8a7961 444 giterr_set(GITERR_REPOSITORY,
7784bcbb 445 "Could not find repository from '%s'", start_path);
904b67e6 446 error = GIT_ENOTFOUND;
97769280 447 }
691aa968 448
7784bcbb
RB
449 return error;
450}
451
a442ed68
VM
452int git_repository_open_bare(
453 git_repository **repo_ptr,
454 const char *bare_path)
455{
456 int error;
457 git_buf path = GIT_BUF_INIT;
458 git_repository *repo = NULL;
459
460 if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0)
461 return error;
462
463 if (!valid_repository_path(&path)) {
464 git_buf_free(&path);
465 giterr_set(GITERR_REPOSITORY, "Path is not a repository: %s", bare_path);
466 return GIT_ENOTFOUND;
467 }
468
469 repo = repository_alloc();
470 GITERR_CHECK_ALLOC(repo);
471
472 repo->path_repository = git_buf_detach(&path);
473 GITERR_CHECK_ALLOC(repo->path_repository);
474
475 /* of course we're bare! */
476 repo->is_bare = 1;
477 repo->workdir = NULL;
478
479 *repo_ptr = repo;
480 return 0;
481}
482
7784bcbb
RB
483int git_repository_open_ext(
484 git_repository **repo_ptr,
485 const char *start_path,
c9fc4a6f 486 unsigned int flags,
7784bcbb
RB
487 const char *ceiling_dirs)
488{
489 int error;
4196dd8e
ET
490 git_buf path = GIT_BUF_INIT, parent = GIT_BUF_INIT,
491 link_path = GIT_BUF_INIT;
7784bcbb 492 git_repository *repo;
16c73d38 493 git_config *config = NULL;
7784bcbb 494
662880ca
RB
495 if (repo_ptr)
496 *repo_ptr = NULL;
7784bcbb 497
4196dd8e
ET
498 error = find_repo(
499 &path, &parent, &link_path, start_path, flags, ceiling_dirs);
500
662880ca 501 if (error < 0 || !repo_ptr)
7784bcbb
RB
502 return error;
503
e52ed7a5 504 repo = repository_alloc();
cb8a7961 505 GITERR_CHECK_ALLOC(repo);
691aa968 506
7784bcbb 507 repo->path_repository = git_buf_detach(&path);
cb8a7961 508 GITERR_CHECK_ALLOC(repo->path_repository);
691aa968 509
4196dd8e
ET
510 if (link_path.size) {
511 repo->path_gitlink = git_buf_detach(&link_path);
512 GITERR_CHECK_ALLOC(repo->path_gitlink);
513 }
514
16c73d38
CMN
515 /*
516 * We'd like to have the config, but git doesn't particularly
517 * care if it's not there, so we need to deal with that.
518 */
519
520 error = git_repository_config_snapshot(&config, repo);
521 if (error < 0 && error != GIT_ENOTFOUND)
522 goto cleanup;
523
524 if (config && (error = check_repositoryformatversion(config)) < 0)
525 goto cleanup;
526
3fe046cf
RB
527 if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0)
528 repo->is_bare = 1;
2b52a0bf 529 else {
2b52a0bf 530
16c73d38
CMN
531 if (config &&
532 ((error = load_config_data(repo, config)) < 0 ||
6a8f3fa8 533 (error = load_workdir(repo, config, &parent)) < 0))
16c73d38 534 goto cleanup;
7784bcbb 535 }
691aa968 536
16c73d38 537cleanup:
146f5c75 538 git_buf_free(&parent);
16c73d38
CMN
539 git_config_free(config);
540
541 if (error < 0)
542 git_repository_free(repo);
543 else
544 *repo_ptr = repo;
2b52a0bf
RB
545
546 return error;
7784bcbb 547}
97769280 548
7784bcbb
RB
549int git_repository_open(git_repository **repo_out, const char *path)
550{
551 return git_repository_open_ext(
552 repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL);
553}
554
6782245e
CMN
555int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb)
556{
557 git_repository *repo;
558
559 repo = repository_alloc();
560 GITERR_CHECK_ALLOC(repo);
561
562 git_repository_set_odb(repo, odb);
563 *repo_out = repo;
564
565 return 0;
566}
567
7784bcbb 568int git_repository_discover(
7a3bd1e7 569 git_buf *out,
7784bcbb
RB
570 const char *start_path,
571 int across_fs,
572 const char *ceiling_dirs)
573{
7784bcbb 574 uint32_t flags = across_fs ? GIT_REPOSITORY_OPEN_CROSS_FS : 0;
7784bcbb 575
7a3bd1e7 576 assert(start_path);
7784bcbb 577
7a3bd1e7 578 git_buf_sanitize(out);
7784bcbb 579
4196dd8e 580 return find_repo(out, NULL, NULL, start_path, flags, ceiling_dirs);
691aa968
VM
581}
582
9462c471 583static int load_config(
7784bcbb
RB
584 git_config **out,
585 git_repository *repo,
586 const char *global_config_path,
4258d483 587 const char *xdg_config_path,
7784bcbb 588 const char *system_config_path)
b22d1479 589{
cc6b4162 590 int error;
97769280 591 git_buf config_path = GIT_BUF_INIT;
9462c471 592 git_config *cfg = NULL;
b22d1479 593
9462c471 594 assert(repo && out);
07ff8817 595
cc6b4162
RB
596 if ((error = git_config_new(&cfg)) < 0)
597 return error;
b22d1479 598
cc6b4162
RB
599 error = git_buf_joinpath(
600 &config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO);
601 if (error < 0)
cb8a7961 602 goto on_error;
97769280 603
cc6b4162
RB
604 if ((error = git_config_add_file_ondisk(
605 cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0 &&
606 error != GIT_ENOTFOUND)
cb8a7961
VM
607 goto on_error;
608
609 git_buf_free(&config_path);
b22d1479 610
cc6b4162
RB
611 if (global_config_path != NULL &&
612 (error = git_config_add_file_ondisk(
613 cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, 0)) < 0 &&
614 error != GIT_ENOTFOUND)
615 goto on_error;
8b4f9b17 616
cc6b4162
RB
617 if (xdg_config_path != NULL &&
618 (error = git_config_add_file_ondisk(
619 cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, 0)) < 0 &&
620 error != GIT_ENOTFOUND)
621 goto on_error;
b22d1479 622
cc6b4162
RB
623 if (system_config_path != NULL &&
624 (error = git_config_add_file_ondisk(
625 cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, 0)) < 0 &&
626 error != GIT_ENOTFOUND)
627 goto on_error;
9ba9e513 628
38f7d026
RB
629 giterr_clear(); /* clear any lingering ENOTFOUND errors */
630
9462c471 631 *out = cfg;
cb8a7961 632 return 0;
b22d1479 633
cb8a7961
VM
634on_error:
635 git_buf_free(&config_path);
9462c471
VM
636 git_config_free(cfg);
637 *out = NULL;
cc6b4162 638 return error;
b22d1479
CMN
639}
640
53607868 641static const char *path_unless_empty(git_buf *buf)
40fe5fbe 642{
53607868
RB
643 return git_buf_len(buf) > 0 ? git_buf_cstr(buf) : NULL;
644}
8b4f9b17 645
53607868
RB
646int git_repository_config__weakptr(git_config **out, git_repository *repo)
647{
648 int error = 0;
40fe5fbe 649
53607868
RB
650 if (repo->_config == NULL) {
651 git_buf global_buf = GIT_BUF_INIT;
652 git_buf xdg_buf = GIT_BUF_INIT;
653 git_buf system_buf = GIT_BUF_INIT;
654 git_config *config;
655
ee550477
CMN
656 git_config_find_global(&global_buf);
657 git_config_find_xdg(&xdg_buf);
658 git_config_find_system(&system_buf);
53607868 659
a4b75dcf
CMN
660 /* If there is no global file, open a backend for it anyway */
661 if (git_buf_len(&global_buf) == 0)
662 git_config__global_location(&global_buf);
663
53607868
RB
664 error = load_config(
665 &config, repo,
666 path_unless_empty(&global_buf),
667 path_unless_empty(&xdg_buf),
668 path_unless_empty(&system_buf));
669 if (!error) {
670 GIT_REFCOUNT_OWN(config, repo);
671
e976b56d 672 config = git__compare_and_swap(&repo->_config, NULL, config);
53607868
RB
673 if (config != NULL) {
674 GIT_REFCOUNT_OWN(config, NULL);
675 git_config_free(config);
676 }
677 }
97769280
RB
678
679 git_buf_free(&global_buf);
a8918418 680 git_buf_free(&xdg_buf);
97769280 681 git_buf_free(&system_buf);
9462c471 682 }
40fe5fbe 683
9462c471 684 *out = repo->_config;
53607868 685 return error;
40fe5fbe
CMN
686}
687
9462c471 688int git_repository_config(git_config **out, git_repository *repo)
fd0574e5 689{
cb8a7961
VM
690 if (git_repository_config__weakptr(out, repo) < 0)
691 return -1;
fd0574e5 692
cb8a7961
VM
693 GIT_REFCOUNT_INC(*out);
694 return 0;
9462c471
VM
695}
696
ac99d86b
CMN
697int git_repository_config_snapshot(git_config **out, git_repository *repo)
698{
b1914c36 699 int error;
ac99d86b
CMN
700 git_config *weak;
701
b1914c36
RB
702 if ((error = git_repository_config__weakptr(&weak, repo)) < 0)
703 return error;
ac99d86b
CMN
704
705 return git_config_snapshot(out, weak);
706}
707
9462c471
VM
708void git_repository_set_config(git_repository *repo, git_config *config)
709{
710 assert(repo && config);
e976b56d 711 set_config(repo, config);
9462c471
VM
712}
713
714int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
715{
53607868
RB
716 int error = 0;
717
9462c471
VM
718 assert(repo && out);
719
720 if (repo->_odb == NULL) {
97769280 721 git_buf odb_path = GIT_BUF_INIT;
53607868 722 git_odb *odb;
9462c471 723
3dbd9a0e
JG
724 if ((error = git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR)) < 0)
725 return error;
9462c471 726
53607868
RB
727 error = git_odb_open(&odb, odb_path.ptr);
728 if (!error) {
729 GIT_REFCOUNT_OWN(odb, repo);
cb8a7961 730
e976b56d 731 odb = git__compare_and_swap(&repo->_odb, NULL, odb);
53607868
RB
732 if (odb != NULL) {
733 GIT_REFCOUNT_OWN(odb, NULL);
734 git_odb_free(odb);
735 }
736 }
9462c471 737
53607868 738 git_buf_free(&odb_path);
9462c471 739 }
fd0574e5 740
9462c471 741 *out = repo->_odb;
53607868 742 return error;
fd0574e5
RG
743}
744
9462c471 745int git_repository_odb(git_odb **out, git_repository *repo)
6fd195d7 746{
cb8a7961
VM
747 if (git_repository_odb__weakptr(out, repo) < 0)
748 return -1;
1795f879 749
cb8a7961
VM
750 GIT_REFCOUNT_INC(*out);
751 return 0;
9462c471 752}
6fd195d7 753
9462c471
VM
754void git_repository_set_odb(git_repository *repo, git_odb *odb)
755{
756 assert(repo && odb);
e976b56d 757 set_odb(repo, odb);
9462c471
VM
758}
759
d00d5464
ET
760int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo)
761{
53607868
RB
762 int error = 0;
763
d00d5464
ET
764 assert(out && repo);
765
766 if (repo->_refdb == NULL) {
53607868 767 git_refdb *refdb;
d00d5464 768
53607868
RB
769 error = git_refdb_open(&refdb, repo);
770 if (!error) {
771 GIT_REFCOUNT_OWN(refdb, repo);
d00d5464 772
e976b56d 773 refdb = git__compare_and_swap(&repo->_refdb, NULL, refdb);
53607868
RB
774 if (refdb != NULL) {
775 GIT_REFCOUNT_OWN(refdb, NULL);
776 git_refdb_free(refdb);
777 }
778 }
d00d5464
ET
779 }
780
781 *out = repo->_refdb;
53607868 782 return error;
d00d5464
ET
783}
784
785int git_repository_refdb(git_refdb **out, git_repository *repo)
786{
787 if (git_repository_refdb__weakptr(out, repo) < 0)
788 return -1;
789
790 GIT_REFCOUNT_INC(*out);
791 return 0;
792}
793
794void git_repository_set_refdb(git_repository *repo, git_refdb *refdb)
795{
53607868 796 assert(repo && refdb);
e976b56d 797 set_refdb(repo, refdb);
d00d5464
ET
798}
799
9462c471
VM
800int git_repository_index__weakptr(git_index **out, git_repository *repo)
801{
53607868
RB
802 int error = 0;
803
9462c471
VM
804 assert(out && repo);
805
9462c471 806 if (repo->_index == NULL) {
97769280 807 git_buf index_path = GIT_BUF_INIT;
53607868 808 git_index *index;
9462c471 809
3dbd9a0e
JG
810 if ((error = git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE)) < 0)
811 return error;
9462c471 812
53607868
RB
813 error = git_index_open(&index, index_path.ptr);
814 if (!error) {
815 GIT_REFCOUNT_OWN(index, repo);
cb8a7961 816
e976b56d 817 index = git__compare_and_swap(&repo->_index, NULL, index);
53607868
RB
818 if (index != NULL) {
819 GIT_REFCOUNT_OWN(index, NULL);
820 git_index_free(index);
821 }
9462c471 822
53607868
RB
823 error = git_index_set_caps(repo->_index, GIT_INDEXCAP_FROM_OWNER);
824 }
da825c92 825
53607868 826 git_buf_free(&index_path);
9462c471
VM
827 }
828
9462c471 829 *out = repo->_index;
53607868 830 return error;
9462c471 831}
1795f879 832
9462c471
VM
833int git_repository_index(git_index **out, git_repository *repo)
834{
cb8a7961
VM
835 if (git_repository_index__weakptr(out, repo) < 0)
836 return -1;
9462c471 837
cb8a7961
VM
838 GIT_REFCOUNT_INC(*out);
839 return 0;
3315782c
VM
840}
841
9462c471
VM
842void git_repository_set_index(git_repository *repo, git_index *index)
843{
fa8ca519 844 assert(repo);
e976b56d 845 set_index(repo, index);
9462c471
VM
846}
847
bade5194
VM
848int git_repository_set_namespace(git_repository *repo, const char *namespace)
849{
850 git__free(repo->namespace);
851
852 if (namespace == NULL) {
853 repo->namespace = NULL;
854 return 0;
855 }
856
857 return (repo->namespace = git__strdup(namespace)) ? 0 : -1;
858}
859
860const char *git_repository_get_namespace(git_repository *repo)
861{
862 return repo->namespace;
863}
864
4196dd8e
ET
865#ifdef GIT_WIN32
866static int reserved_names_add8dot3(git_repository *repo, const char *path)
a64119e3 867{
4196dd8e
ET
868 char *name = git_win32_path_8dot3_name(path);
869 const char *def = GIT_DIR_SHORTNAME;
526f91f5 870 const char *def_dot_git = DOT_GIT;
4196dd8e 871 size_t name_len, def_len = CONST_STRLEN(GIT_DIR_SHORTNAME);
526f91f5 872 size_t def_dot_git_len = CONST_STRLEN(DOT_GIT);
4196dd8e 873 git_buf *buf;
a64119e3 874
4196dd8e
ET
875 if (!name)
876 return 0;
877
878 name_len = strlen(name);
879
526f91f5
L
880 if ((name_len == def_len && memcmp(name, def, def_len) == 0) ||
881 (name_len == def_dot_git_len && memcmp(name, def_dot_git, def_dot_git_len) == 0)) {
4196dd8e
ET
882 git__free(name);
883 return 0;
884 }
885
886 if ((buf = git_array_alloc(repo->reserved_names)) == NULL)
887 return -1;
888
889 git_buf_attach(buf, name, name_len);
890 return true;
891}
892
893bool git_repository__reserved_names(
894 git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs)
895{
896 GIT_UNUSED(include_ntfs);
897
898 if (repo->reserved_names.size == 0) {
899 git_buf *buf;
900 size_t i;
901
902 /* Add the static defaults */
903 for (i = 0; i < git_repository__reserved_names_win32_len; i++) {
904 if ((buf = git_array_alloc(repo->reserved_names)) == NULL)
905 goto on_error;
906
907 buf->ptr = git_repository__reserved_names_win32[i].ptr;
908 buf->size = git_repository__reserved_names_win32[i].size;
909 }
910
911 /* Try to add any repo-specific reserved names */
a64119e3 912 if (!repo->is_bare) {
4196dd8e
ET
913 const char *reserved_path = repo->path_gitlink ?
914 repo->path_gitlink : repo->path_repository;
a64119e3 915
4196dd8e
ET
916 if (reserved_names_add8dot3(repo, reserved_path) < 0)
917 goto on_error;
a64119e3 918 }
a64119e3
ET
919 }
920
4196dd8e
ET
921 *out = repo->reserved_names.ptr;
922 *outlen = repo->reserved_names.size;
923
924 return true;
925
926 /* Always give good defaults, even on OOM */
927on_error:
928 *out = git_repository__reserved_names_win32;
929 *outlen = git_repository__reserved_names_win32_len;
930
931 return false;
a64119e3 932}
4196dd8e
ET
933#else
934bool git_repository__reserved_names(
935 git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs)
936{
937 GIT_UNUSED(repo);
938
939 if (include_ntfs) {
940 *out = git_repository__reserved_names_win32;
941 *outlen = git_repository__reserved_names_win32_len;
942 } else {
943 *out = git_repository__reserved_names_posix;
944 *outlen = git_repository__reserved_names_posix_len;
945 }
946
947 return true;
948}
949#endif
a64119e3 950
2c227b8b 951static int check_repositoryformatversion(git_config *config)
40c44d2f 952{
99e11cdd 953 int version, error;
5663e61a 954
99e11cdd
CMN
955 error = git_config_get_int32(&version, config, "core.repositoryformatversion");
956 /* git ignores this if the config variable isn't there */
957 if (error == GIT_ENOTFOUND)
958 return 0;
959
960 if (error < 0)
cb8a7961 961 return -1;
5663e61a 962
29e948de 963 if (GIT_REPO_VERSION < version) {
cb8a7961
VM
964 giterr_set(GITERR_REPOSITORY,
965 "Unsupported repository version %d. Only versions up to %d are supported.",
29e948de 966 version, GIT_REPO_VERSION);
cb8a7961
VM
967 return -1;
968 }
5663e61a 969
cb8a7961 970 return 0;
5663e61a 971}
972
662880ca 973static int repo_init_create_head(const char *git_dir, const char *ref_name)
e1f8cad0 974{
97769280 975 git_buf ref_path = GIT_BUF_INIT;
9462c471 976 git_filebuf ref = GIT_FILEBUF_INIT;
662880ca 977 const char *fmt;
9462c471 978
cb8a7961 979 if (git_buf_joinpath(&ref_path, git_dir, GIT_HEAD_FILE) < 0 ||
1d3a8aeb 980 git_filebuf_open(&ref, ref_path.ptr, 0, GIT_REFS_FILE_MODE) < 0)
662880ca
RB
981 goto fail;
982
983 if (!ref_name)
984 ref_name = GIT_BRANCH_MASTER;
985
74a24005 986 if (git__prefixcmp(ref_name, GIT_REFS_DIR) == 0)
662880ca
RB
987 fmt = "ref: %s\n";
988 else
74a24005 989 fmt = "ref: " GIT_REFS_HEADS_DIR "%s\n";
662880ca
RB
990
991 if (git_filebuf_printf(&ref, fmt, ref_name) < 0 ||
1d3a8aeb 992 git_filebuf_commit(&ref) < 0)
662880ca 993 goto fail;
9462c471 994
97769280 995 git_buf_free(&ref_path);
cb8a7961 996 return 0;
662880ca
RB
997
998fail:
999 git_buf_free(&ref_path);
1000 git_filebuf_cleanup(&ref);
1001 return -1;
9462c471
VM
1002}
1003
fac66990 1004static bool is_chmod_supported(const char *file_path)
1005{
1006 struct stat st1, st2;
fac66990 1007
1008 if (p_stat(file_path, &st1) < 0)
1009 return false;
1010
1011 if (p_chmod(file_path, st1.st_mode ^ S_IXUSR) < 0)
1012 return false;
1013
1014 if (p_stat(file_path, &st2) < 0)
1015 return false;
1016
6b7991e2 1017 return (st1.st_mode != st2.st_mode);
fac66990 1018}
1019
693b23c0 1020static bool is_filesystem_case_insensitive(const char *gitdir_path)
1021{
1022 git_buf path = GIT_BUF_INIT;
6b7991e2 1023 int is_insensitive = -1;
693b23c0 1024
6b7991e2
RB
1025 if (!git_buf_joinpath(&path, gitdir_path, "CoNfIg"))
1026 is_insensitive = git_path_exists(git_buf_cstr(&path));
693b23c0 1027
693b23c0 1028 git_buf_free(&path);
6b7991e2 1029 return is_insensitive;
693b23c0 1030}
1031
ca1b6e54
RB
1032static bool are_symlinks_supported(const char *wd_path)
1033{
1034 git_buf path = GIT_BUF_INIT;
1035 int fd;
1036 struct stat st;
6b7991e2 1037 int symlinks_supported = -1;
ca1b6e54 1038
1d3a8aeb 1039 if ((fd = git_futils_mktmp(&path, wd_path, 0666)) < 0 ||
ca1b6e54
RB
1040 p_close(fd) < 0 ||
1041 p_unlink(path.ptr) < 0 ||
1042 p_symlink("testing", path.ptr) < 0 ||
1043 p_lstat(path.ptr, &st) < 0)
6b7991e2 1044 symlinks_supported = false;
ca1b6e54 1045 else
6b7991e2 1046 symlinks_supported = (S_ISLNK(st.st_mode) != 0);
ca1b6e54
RB
1047
1048 (void)p_unlink(path.ptr);
1049 git_buf_free(&path);
1050
6b7991e2
RB
1051 return symlinks_supported;
1052}
1053
270160b9 1054static int create_empty_file(const char *path, mode_t mode)
1055{
1056 int fd;
1057
1058 if ((fd = p_creat(path, mode)) < 0) {
1059 giterr_set(GITERR_OS, "Error while creating '%s'", path);
1060 return -1;
1061 }
1062
1063 if (p_close(fd) < 0) {
1064 giterr_set(GITERR_OS, "Error while closing '%s'", path);
1065 return -1;
1066 }
1067
1068 return 0;
1069}
1070
14997dc5
RB
1071static int repo_local_config(
1072 git_config **out,
1073 git_buf *config_dir,
1074 git_repository *repo,
1075 const char *repo_dir)
9462c471 1076{
ca1b6e54 1077 int error = 0;
14997dc5
RB
1078 git_config *parent;
1079 const char *cfg_path;
9462c471 1080
14997dc5 1081 if (git_buf_joinpath(config_dir, repo_dir, GIT_CONFIG_FILENAME_INREPO) < 0)
cb8a7961 1082 return -1;
14997dc5 1083 cfg_path = git_buf_cstr(config_dir);
9462c471 1084
14997dc5 1085 /* make LOCAL config if missing */
5173ea92
RB
1086 if (!git_path_isfile(cfg_path) &&
1087 (error = create_empty_file(cfg_path, GIT_CONFIG_FILE_MODE)) < 0)
14997dc5 1088 return error;
270160b9 1089
14997dc5
RB
1090 /* if no repo, just open that file directly */
1091 if (!repo)
1092 return git_config_open_ondisk(out, cfg_path);
1093
1094 /* otherwise, open parent config and get that level */
1095 if ((error = git_repository_config__weakptr(&parent, repo)) < 0)
1096 return error;
1097
1098 if (git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL) < 0) {
5173ea92
RB
1099 giterr_clear();
1100
1101 if (!(error = git_config_add_file_ondisk(
1102 parent, cfg_path, GIT_CONFIG_LEVEL_LOCAL, false)))
14997dc5 1103 error = git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL);
cb8a7961 1104 }
9462c471 1105
14997dc5
RB
1106 git_config_free(parent);
1107
1108 return error;
1109}
1110
1111static int repo_init_fs_configs(
1112 git_config *cfg,
1113 const char *cfg_path,
1114 const char *repo_dir,
1115 const char *work_dir,
1116 bool update_ignorecase)
1117{
1118 int error = 0;
1119
1120 if (!work_dir)
1121 work_dir = repo_dir;
1122
1123 if ((error = git_config_set_bool(
1124 cfg, "core.filemode", is_chmod_supported(cfg_path))) < 0)
1125 return error;
1126
1127 if (!are_symlinks_supported(work_dir)) {
1128 if ((error = git_config_set_bool(cfg, "core.symlinks", false)) < 0)
1129 return error;
1130 } else if (git_config_delete_entry(cfg, "core.symlinks") < 0)
1131 giterr_clear();
2c227b8b 1132
14997dc5
RB
1133 if (update_ignorecase) {
1134 if (is_filesystem_case_insensitive(repo_dir)) {
1135 if ((error = git_config_set_bool(cfg, "core.ignorecase", true)) < 0)
1136 return error;
1137 } else if (git_config_delete_entry(cfg, "core.ignorecase") < 0)
1138 giterr_clear();
1139 }
662880ca 1140
af302aca 1141#ifdef GIT_USE_ICONV
14997dc5
RB
1142 if ((error = git_config_set_bool(
1143 cfg, "core.precomposeunicode",
43a04135 1144 git_path_does_fs_decompose_unicode(work_dir))) < 0)
14997dc5 1145 return error;
43a04135 1146 /* on non-iconv platforms, don't even set core.precomposeunicode */
6b7991e2
RB
1147#endif
1148
14997dc5
RB
1149 return 0;
1150}
7623b1b6 1151
14997dc5
RB
1152static int repo_init_config(
1153 const char *repo_dir,
1154 const char *work_dir,
1155 uint32_t flags,
1156 uint32_t mode)
1157{
1158 int error = 0;
bc737620 1159 git_buf cfg_path = GIT_BUF_INIT, worktree_path = GIT_BUF_INIT;
14997dc5
RB
1160 git_config *config = NULL;
1161 bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
1162 bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
1163
1164 if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0)
1165 goto cleanup;
1166
1167 if (is_reinit && (error = check_repositoryformatversion(config)) < 0)
1168 goto cleanup;
1169
1170#define SET_REPO_CONFIG(TYPE, NAME, VAL) do { \
1171 if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \
1172 goto cleanup; } while (0)
1173
1174 SET_REPO_CONFIG(bool, "core.bare", is_bare);
1175 SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION);
1176
1177 if ((error = repo_init_fs_configs(
1178 config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0)
1179 goto cleanup;
5173ea92 1180
6b7991e2
RB
1181 if (!is_bare) {
1182 SET_REPO_CONFIG(bool, "core.logallrefupdates", true);
ca1b6e54 1183
bc737620
JM
1184 if (!(flags & GIT_REPOSITORY_INIT__NATURAL_WD)) {
1185 if ((error = git_buf_sets(&worktree_path, work_dir)) < 0)
1186 goto cleanup;
1187
1188 if ((flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK))
1189 if ((error = git_path_make_relative(&worktree_path, repo_dir)) < 0)
1190 goto cleanup;
1191
1192 SET_REPO_CONFIG(string, "core.worktree", worktree_path.ptr);
1193 } else if (is_reinit) {
54b2a37a 1194 if (git_config_delete_entry(config, "core.worktree") < 0)
89cd5708 1195 giterr_clear();
ca1b6e54 1196 }
ca1b6e54
RB
1197 }
1198
5173ea92 1199 if (mode == GIT_REPOSITORY_INIT_SHARED_GROUP) {
662880ca
RB
1200 SET_REPO_CONFIG(int32, "core.sharedrepository", 1);
1201 SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true);
ca1b6e54 1202 }
5173ea92 1203 else if (mode == GIT_REPOSITORY_INIT_SHARED_ALL) {
662880ca
RB
1204 SET_REPO_CONFIG(int32, "core.sharedrepository", 2);
1205 SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true);
1206 }
9462c471 1207
ca1b6e54 1208cleanup:
14997dc5 1209 git_buf_free(&cfg_path);
bc737620 1210 git_buf_free(&worktree_path);
9462c471 1211 git_config_free(config);
662880ca 1212
ca1b6e54 1213 return error;
d2d6912e 1214}
e1f8cad0 1215
867f7c9b 1216static int repo_reinit_submodule_fs(git_submodule *sm, const char *n, void *p)
5173ea92 1217{
14997dc5
RB
1218 git_repository *smrepo = NULL;
1219 GIT_UNUSED(n); GIT_UNUSED(p);
5173ea92 1220
14997dc5 1221 if (git_submodule_open(&smrepo, sm) < 0 ||
867f7c9b 1222 git_repository_reinit_filesystem(smrepo, true) < 0)
14997dc5
RB
1223 giterr_clear();
1224 git_repository_free(smrepo);
5173ea92 1225
14997dc5
RB
1226 return 0;
1227}
5173ea92 1228
867f7c9b 1229int git_repository_reinit_filesystem(git_repository *repo, int recurse)
14997dc5
RB
1230{
1231 int error = 0;
1232 git_buf path = GIT_BUF_INIT;
1233 git_config *config = NULL;
1234 const char *repo_dir = git_repository_path(repo);
5173ea92 1235
14997dc5
RB
1236 if (!(error = repo_local_config(&config, &path, repo, repo_dir)))
1237 error = repo_init_fs_configs(
1238 config, path.ptr, repo_dir, git_repository_workdir(repo), true);
5173ea92 1239
14997dc5
RB
1240 git_config_free(config);
1241 git_buf_free(&path);
5173ea92 1242
5173ea92
RB
1243 git_repository__cvar_cache_clear(repo);
1244
14997dc5 1245 if (!repo->is_bare && recurse)
867f7c9b 1246 (void)git_submodule_foreach(repo, repo_reinit_submodule_fs, NULL);
14997dc5 1247
5173ea92
RB
1248 return error;
1249}
1250
dc34da6e 1251static int repo_write_template(
991a56c7
RB
1252 const char *git_dir,
1253 bool allow_overwrite,
1254 const char *file,
1255 mode_t mode,
662880ca 1256 bool hidden,
991a56c7 1257 const char *content)
dc34da6e
RB
1258{
1259 git_buf path = GIT_BUF_INIT;
991a56c7 1260 int fd, error = 0, flags;
dc34da6e
RB
1261
1262 if (git_buf_joinpath(&path, git_dir, file) < 0)
1263 return -1;
1264
991a56c7
RB
1265 if (allow_overwrite)
1266 flags = O_WRONLY | O_CREAT | O_TRUNC;
1267 else
1268 flags = O_WRONLY | O_CREAT | O_EXCL;
1269
1270 fd = p_open(git_buf_cstr(&path), flags, mode);
dc34da6e 1271
db628072
RB
1272 if (fd >= 0) {
1273 error = p_write(fd, content, strlen(content));
dc34da6e 1274
db628072
RB
1275 p_close(fd);
1276 }
1277 else if (errno != EEXIST)
1278 error = fd;
dc34da6e 1279
662880ca
RB
1280#ifdef GIT_WIN32
1281 if (!error && hidden) {
c2c81615 1282 if (git_win32__sethidden(path.ptr) < 0)
662880ca
RB
1283 error = -1;
1284 }
1285#else
1286 GIT_UNUSED(hidden);
1287#endif
1288
dc34da6e 1289 git_buf_free(&path);
db628072
RB
1290
1291 if (error)
1292 giterr_set(GITERR_OS,
1293 "Failed to initialize repository with template '%s'", file);
1294
1295 return error;
dc34da6e
RB
1296}
1297
662880ca 1298static int repo_write_gitlink(
bc737620 1299 const char *in_dir, const char *to_repo, bool use_relative_path)
4b8e27c8 1300{
662880ca
RB
1301 int error;
1302 git_buf buf = GIT_BUF_INIT;
bc737620 1303 git_buf path_to_repo = GIT_BUF_INIT;
662880ca
RB
1304 struct stat st;
1305
1306 git_path_dirname_r(&buf, to_repo);
1307 git_path_to_dir(&buf);
1308 if (git_buf_oom(&buf))
cb8a7961 1309 return -1;
a67a096a 1310
662880ca
RB
1311 /* don't write gitlink to natural workdir */
1312 if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 &&
1313 strcmp(in_dir, buf.ptr) == 0)
1314 {
1315 error = GIT_PASSTHROUGH;
1316 goto cleanup;
1317 }
1318
1319 if ((error = git_buf_joinpath(&buf, in_dir, DOT_GIT)) < 0)
1320 goto cleanup;
1321
1322 if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) {
1323 giterr_set(GITERR_REPOSITORY,
1324 "Cannot overwrite gitlink file into path '%s'", in_dir);
1325 error = GIT_EEXISTS;
1326 goto cleanup;
1327 }
1328
1329 git_buf_clear(&buf);
1330
bc737620
JM
1331 error = git_buf_sets(&path_to_repo, to_repo);
1332
1333 if (!error && use_relative_path)
1334 error = git_path_make_relative(&path_to_repo, in_dir);
1335
1336 if (!error)
1337 error = git_buf_join(&buf, ' ', GIT_FILE_CONTENT_PREFIX, path_to_repo.ptr);
662880ca
RB
1338
1339 if (!error)
18f08264 1340 error = repo_write_template(in_dir, true, DOT_GIT, 0666, true, buf.ptr);
662880ca
RB
1341
1342cleanup:
1343 git_buf_free(&buf);
bc737620 1344 git_buf_free(&path_to_repo);
662880ca
RB
1345 return error;
1346}
1347
ca1b6e54
RB
1348static mode_t pick_dir_mode(git_repository_init_options *opts)
1349{
1350 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_UMASK)
18f08264 1351 return 0777;
ca1b6e54
RB
1352 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_GROUP)
1353 return (0775 | S_ISGID);
1354 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_ALL)
1355 return (0777 | S_ISGID);
1356 return opts->mode;
1357}
1358
662880ca
RB
1359#include "repo_template.h"
1360
1361static int repo_init_structure(
1362 const char *repo_dir,
1363 const char *work_dir,
1364 git_repository_init_options *opts)
1365{
ca1b6e54 1366 int error = 0;
662880ca 1367 repo_template_item *tpl;
ca1b6e54
RB
1368 bool external_tpl =
1369 ((opts->flags & GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) != 0);
1370 mode_t dmode = pick_dir_mode(opts);
bafaf790 1371 bool chmod = opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK;
662880ca
RB
1372
1373 /* Hide the ".git" directory */
17837602 1374#ifdef GIT_WIN32
2eb4edf5 1375 if ((opts->flags & GIT_REPOSITORY_INIT__HAS_DOTGIT) != 0) {
c2c81615
PK
1376 if (git_win32__sethidden(repo_dir) < 0) {
1377 giterr_set(GITERR_OS,
cb8a7961
VM
1378 "Failed to mark Git repository folder as hidden");
1379 return -1;
1380 }
17837602 1381 }
2eb4edf5
RB
1382#endif
1383
1384 /* Create the .git gitlink if appropriate */
1385 if ((opts->flags & GIT_REPOSITORY_INIT_BARE) == 0 &&
1386 (opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD) == 0)
1387 {
bc737620 1388 if (repo_write_gitlink(work_dir, repo_dir, opts->flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK) < 0)
cb8a7961 1389 return -1;
97769280 1390 }
1c2c7c0d 1391
ca1b6e54
RB
1392 /* Copy external template if requested */
1393 if (external_tpl) {
0cd1c3bb
L
1394 git_config *cfg = NULL;
1395 const char *tdir = NULL;
1396 bool default_template = false;
a025907e
L
1397 git_buf template_buf = GIT_BUF_INIT;
1398
ca1b6e54
RB
1399 if (opts->template_path)
1400 tdir = opts->template_path;
0cd1c3bb 1401 else if ((error = git_config_open_default(&cfg)) >= 0) {
cc36f424
CMN
1402 if (!git_config_get_path(&template_buf, cfg, "init.templatedir"))
1403 tdir = template_buf.ptr;
ca1b6e54 1404 giterr_clear();
0cd1c3bb
L
1405 }
1406
1407 if (!tdir) {
83634d38 1408 if (!(error = git_sysdir_find_template_dir(&template_buf)))
417472e3 1409 tdir = template_buf.ptr;
0cd1c3bb 1410 default_template = true;
662880ca 1411 }
ca1b6e54 1412
bafaf790 1413 if (tdir) {
517341c5
EL
1414 uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS | GIT_CPDIR_SIMPLE_TO_MODE;
1415 if (opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK)
1416 cpflags |= GIT_CPDIR_CHMOD_DIRS;
1417 error = git_futils_cp_r(tdir, repo_dir, cpflags, dmode);
bafaf790 1418 }
ca1b6e54 1419
0cd1c3bb
L
1420 git_buf_free(&template_buf);
1421 git_config_free(cfg);
1ca3e49f 1422
ca1b6e54 1423 if (error < 0) {
0cd1c3bb 1424 if (!default_template)
ca1b6e54
RB
1425 return error;
1426
1427 /* if template was default, ignore error and use internal */
1428 giterr_clear();
1429 external_tpl = false;
b7b1acfd 1430 error = 0;
ca1b6e54
RB
1431 }
1432 }
1433
1434 /* Copy internal template
1435 * - always ensure existence of dirs
1436 * - only create files if no external template was specified
1437 */
1438 for (tpl = repo_template; !error && tpl->path; ++tpl) {
bafaf790 1439 if (!tpl->content) {
517341c5
EL
1440 uint32_t mkdir_flags = GIT_MKDIR_PATH;
1441 if (chmod)
1442 mkdir_flags |= GIT_MKDIR_CHMOD;
1443
1444 error = git_futils_mkdir(
1445 tpl->path, repo_dir, dmode, mkdir_flags);
bafaf790 1446 }
ca1b6e54 1447 else if (!external_tpl) {
662880ca
RB
1448 const char *content = tpl->content;
1449
1450 if (opts->description && strcmp(tpl->path, GIT_DESC_FILE) == 0)
1451 content = opts->description;
1452
ca1b6e54
RB
1453 error = repo_write_template(
1454 repo_dir, false, tpl->path, tpl->mode, false, content);
662880ca 1455 }
dc34da6e
RB
1456 }
1457
ca1b6e54 1458 return error;
4b8e27c8 1459}
1460
3c42e4ef
RB
1461static int mkdir_parent(git_buf *buf, uint32_t mode, bool skip2)
1462{
0d1b094b
RB
1463 /* When making parent directories during repository initialization
1464 * don't try to set gid or grant world write access
1465 */
3c42e4ef 1466 return git_futils_mkdir(
0d1b094b 1467 buf->ptr, NULL, mode & ~(S_ISGID | 0002),
3c42e4ef
RB
1468 GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR |
1469 (skip2 ? GIT_MKDIR_SKIP_LAST2 : GIT_MKDIR_SKIP_LAST));
1470}
1471
662880ca
RB
1472static int repo_init_directories(
1473 git_buf *repo_path,
1474 git_buf *wd_path,
1475 const char *given_repo,
1476 git_repository_init_options *opts)
4b8e27c8 1477{
662880ca 1478 int error = 0;
3c42e4ef 1479 bool is_bare, add_dotgit, has_dotgit, natural_wd;
ca1b6e54 1480 mode_t dirmode;
932d1baf 1481
3c42e4ef
RB
1482 /* There are three possible rules for what we are allowed to create:
1483 * - MKPATH means anything we need
1484 * - MKDIR means just the .git directory and its parent and the workdir
1485 * - Neither means only the .git directory can be created
1486 *
1487 * There are 5 "segments" of path that we might need to deal with:
1488 * 1. The .git directory
1489 * 2. The parent of the .git directory
1490 * 3. Everything above the parent of the .git directory
1491 * 4. The working directory (often the same as #2)
1492 * 5. Everything above the working directory (often the same as #3)
1493 *
1494 * For all directories created, we start with the init_mode value for
1495 * permissions and then strip off bits in some cases:
1496 *
1497 * For MKPATH, we create #3 (and #5) paths without S_ISGID or S_IWOTH
1498 * For MKPATH and MKDIR, we create #2 (and #4) without S_ISGID
1499 * For all rules, we create #1 using the untouched init_mode
1500 */
1501
662880ca 1502 /* set up repo path */
4b8e27c8 1503
3c42e4ef
RB
1504 is_bare = ((opts->flags & GIT_REPOSITORY_INIT_BARE) != 0);
1505
662880ca
RB
1506 add_dotgit =
1507 (opts->flags & GIT_REPOSITORY_INIT_NO_DOTGIT_DIR) == 0 &&
3c42e4ef 1508 !is_bare &&
662880ca
RB
1509 git__suffixcmp(given_repo, "/" DOT_GIT) != 0 &&
1510 git__suffixcmp(given_repo, "/" GIT_DIR) != 0;
4b8e27c8 1511
662880ca
RB
1512 if (git_buf_joinpath(repo_path, given_repo, add_dotgit ? GIT_DIR : "") < 0)
1513 return -1;
693b23c0 1514
662880ca
RB
1515 has_dotgit = (git__suffixcmp(repo_path->ptr, "/" GIT_DIR) == 0);
1516 if (has_dotgit)
1517 opts->flags |= GIT_REPOSITORY_INIT__HAS_DOTGIT;
1518
1519 /* set up workdir path */
1520
3c42e4ef 1521 if (!is_bare) {
662880ca 1522 if (opts->workdir_path) {
ca1b6e54
RB
1523 if (git_path_join_unrooted(
1524 wd_path, opts->workdir_path, repo_path->ptr, NULL) < 0)
1525 return -1;
662880ca
RB
1526 } else if (has_dotgit) {
1527 if (git_path_dirname_r(wd_path, repo_path->ptr) < 0)
1528 return -1;
1529 } else {
1530 giterr_set(GITERR_REPOSITORY, "Cannot pick working directory"
1531 " for non-bare repository that isn't a '.git' directory");
1532 return -1;
1533 }
693b23c0 1534
662880ca
RB
1535 if (git_path_to_dir(wd_path) < 0)
1536 return -1;
1537 } else {
1538 git_buf_clear(wd_path);
1539 }
1540
1541 natural_wd =
1542 has_dotgit &&
1543 wd_path->size > 0 &&
1544 wd_path->size + strlen(GIT_DIR) == repo_path->size &&
1545 memcmp(repo_path->ptr, wd_path->ptr, wd_path->size) == 0;
1546 if (natural_wd)
1547 opts->flags |= GIT_REPOSITORY_INIT__NATURAL_WD;
1548
662880ca
RB
1549 /* create directories as needed / requested */
1550
ca1b6e54 1551 dirmode = pick_dir_mode(opts);
662880ca 1552
3c42e4ef
RB
1553 if ((opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) {
1554 /* create path #5 */
1555 if (wd_path->size > 0 &&
1556 (error = mkdir_parent(wd_path, dirmode, false)) < 0)
1557 return error;
1558
1559 /* create path #3 (if not the same as #5) */
1560 if (!natural_wd &&
1561 (error = mkdir_parent(repo_path, dirmode, has_dotgit)) < 0)
1562 return error;
1563 }
1564
1565 if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 ||
1566 (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0)
1567 {
1568 /* create path #4 */
1569 if (wd_path->size > 0 &&
1570 (error = git_futils_mkdir(
1571 wd_path->ptr, NULL, dirmode & ~S_ISGID,
1572 GIT_MKDIR_VERIFY_DIR)) < 0)
1573 return error;
1574
1575 /* create path #2 (if not the same as #4) */
1576 if (!natural_wd &&
1577 (error = git_futils_mkdir(
1578 repo_path->ptr, NULL, dirmode & ~S_ISGID,
1579 GIT_MKDIR_VERIFY_DIR | GIT_MKDIR_SKIP_LAST)) < 0)
1580 return error;
662880ca 1581 }
662880ca 1582
ca1b6e54
RB
1583 if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 ||
1584 (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0 ||
1585 has_dotgit)
1586 {
3c42e4ef 1587 /* create path #1 */
18f08264
RB
1588 error = git_futils_mkdir(repo_path->ptr, NULL, dirmode,
1589 GIT_MKDIR_VERIFY_DIR | ((dirmode & S_ISGID) ? GIT_MKDIR_CHMOD : 0));
662880ca 1590 }
ca1b6e54 1591
662880ca
RB
1592 /* prettify both directories now that they are created */
1593
1594 if (!error) {
1595 error = git_path_prettify_dir(repo_path, repo_path->ptr, NULL);
1596
1597 if (!error && wd_path->size > 0)
1598 error = git_path_prettify_dir(wd_path, wd_path->ptr, NULL);
1599 }
1600
1601 return error;
1602}
1603
1604static int repo_init_create_origin(git_repository *repo, const char *url)
1605{
1606 int error;
1607 git_remote *remote;
1608
29f27599 1609 if (!(error = git_remote_create(&remote, repo, GIT_REMOTE_ORIGIN, url))) {
662880ca
RB
1610 git_remote_free(remote);
1611 }
1612
1613 return error;
1614}
1615
1616int git_repository_init(
1617 git_repository **repo_out, const char *path, unsigned is_bare)
1618{
b4d13652 1619 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
662880ca 1620
662880ca
RB
1621 opts.flags = GIT_REPOSITORY_INIT_MKPATH; /* don't love this default */
1622 if (is_bare)
1623 opts.flags |= GIT_REPOSITORY_INIT_BARE;
1624
1625 return git_repository_init_ext(repo_out, path, &opts);
1626}
1627
1628int git_repository_init_ext(
c9fc4a6f 1629 git_repository **out,
662880ca
RB
1630 const char *given_repo,
1631 git_repository_init_options *opts)
1632{
1633 int error;
1634 git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT;
466d2e7a 1635 const char *wd;
662880ca 1636
c9fc4a6f 1637 assert(out && given_repo && opts);
662880ca 1638
c7231c45 1639 GITERR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options");
b4d13652 1640
662880ca
RB
1641 error = repo_init_directories(&repo_path, &wd_path, given_repo, opts);
1642 if (error < 0)
693b23c0 1643 goto cleanup;
662880ca 1644
466d2e7a 1645 wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_buf_cstr(&wd_path);
662880ca
RB
1646 if (valid_repository_path(&repo_path)) {
1647
1648 if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) {
1649 giterr_set(GITERR_REPOSITORY,
1650 "Attempt to reinitialize '%s'", given_repo);
1651 error = GIT_EEXISTS;
1652 goto cleanup;
1653 }
1654
1655 opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT;
1656
ca1b6e54 1657 error = repo_init_config(
466d2e7a 1658 repo_path.ptr, wd, opts->flags, opts->mode);
662880ca
RB
1659
1660 /* TODO: reinitialize the templates */
1661 }
1662 else {
1663 if (!(error = repo_init_structure(
466d2e7a 1664 repo_path.ptr, wd, opts)) &&
ca1b6e54 1665 !(error = repo_init_config(
466d2e7a 1666 repo_path.ptr, wd, opts->flags, opts->mode)))
662880ca 1667 error = repo_init_create_head(
5173ea92 1668 repo_path.ptr, opts->initial_head);
cb8a7961 1669 }
662880ca
RB
1670 if (error < 0)
1671 goto cleanup;
1672
5173ea92 1673 error = git_repository_open(out, repo_path.ptr);
d2d6912e 1674
662880ca 1675 if (!error && opts->origin_url)
c9fc4a6f 1676 error = repo_init_create_origin(*out, opts->origin_url);
693b23c0 1677
1678cleanup:
662880ca
RB
1679 git_buf_free(&repo_path);
1680 git_buf_free(&wd_path);
1681
1682 return error;
40c44d2f 1683}
35502d2e 1684
c682886e 1685int git_repository_head_detached(git_repository *repo)
35502d2e
CMN
1686{
1687 git_reference *ref;
9462c471 1688 git_odb *odb = NULL;
cb8a7961 1689 int exists;
9462c471 1690
cb8a7961
VM
1691 if (git_repository_odb__weakptr(&odb, repo) < 0)
1692 return -1;
35502d2e 1693
cb8a7961
VM
1694 if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0)
1695 return -1;
35502d2e 1696
75abd2b9
MS
1697 if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1698 git_reference_free(ref);
35502d2e 1699 return 0;
75abd2b9 1700 }
35502d2e 1701
2508cc66 1702 exists = git_odb_exists(odb, git_reference_target(ref));
75abd2b9
MS
1703
1704 git_reference_free(ref);
cb8a7961 1705 return exists;
35502d2e
CMN
1706}
1707
3601c4bf 1708int git_repository_head(git_reference **head_out, git_repository *repo)
35502d2e 1709{
b1a3a70e 1710 git_reference *head;
8b05bea8 1711 int error;
1712
b1a3a70e 1713 if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
1714 return error;
1715
1716 if (git_reference_type(head) == GIT_REF_OID) {
1717 *head_out = head;
1718 return 0;
1719 }
1720
2508cc66 1721 error = git_reference_lookup_resolved(head_out, repo, git_reference_symbolic_target(head), -1);
b1a3a70e 1722 git_reference_free(head);
8b05bea8 1723
605da51a 1724 return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error;
3601c4bf 1725}
1726
605da51a 1727int git_repository_head_unborn(git_repository *repo)
3601c4bf 1728{
cb8a7961 1729 git_reference *ref = NULL;
3601c4bf 1730 int error;
1731
1732 error = git_repository_head(&ref, repo);
cb8a7961 1733 git_reference_free(ref);
35502d2e 1734
7c9bf891
ET
1735 if (error == GIT_EUNBORNBRANCH) {
1736 giterr_clear();
cb8a7961 1737 return 1;
7c9bf891 1738 }
75abd2b9 1739
cb8a7961
VM
1740 if (error < 0)
1741 return -1;
1742
1743 return 0;
35502d2e 1744}
e0011be3 1745
0066955d 1746static int at_least_one_cb(const char *refname, void *payload)
41233c40 1747{
6091457e 1748 GIT_UNUSED(refname);
1749 GIT_UNUSED(payload);
25e0b157 1750 return GIT_PASSTHROUGH;
6091457e 1751}
41233c40 1752
6091457e 1753static int repo_contains_no_reference(git_repository *repo)
1754{
ec24e542 1755 int error = git_reference_foreach_name(repo, &at_least_one_cb, NULL);
0f489fb2 1756
25e0b157 1757 if (error == GIT_PASSTHROUGH)
0f489fb2 1758 return 0;
ec24e542 1759
e976b56d
RB
1760 if (!error)
1761 return 1;
ec24e542 1762
e976b56d 1763 return error;
6091457e 1764}
75abd2b9 1765
6091457e 1766int git_repository_is_empty(git_repository *repo)
1767{
1768 git_reference *head = NULL;
42181836 1769 int is_empty = 0;
cb8a7961 1770
6091457e 1771 if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0)
cb8a7961
VM
1772 return -1;
1773
42181836
RB
1774 if (git_reference_type(head) == GIT_REF_SYMBOLIC)
1775 is_empty =
1776 (strcmp(git_reference_symbolic_target(head),
1777 GIT_REFS_HEADS_DIR "master") == 0) &&
1778 repo_contains_no_reference(repo);
6091457e 1779
6091457e 1780 git_reference_free(head);
42181836
RB
1781
1782 return is_empty;
41233c40
VM
1783}
1784
9462c471 1785const char *git_repository_path(git_repository *repo)
4a34b3a9 1786{
1787 assert(repo);
9462c471
VM
1788 return repo->path_repository;
1789}
4a34b3a9 1790
9462c471
VM
1791const char *git_repository_workdir(git_repository *repo)
1792{
1793 assert(repo);
602ee38b 1794
9462c471
VM
1795 if (repo->is_bare)
1796 return NULL;
602ee38b 1797
9462c471
VM
1798 return repo->workdir;
1799}
602ee38b 1800
991a56c7
RB
1801int git_repository_set_workdir(
1802 git_repository *repo, const char *workdir, int update_gitlink)
9462c471 1803{
991a56c7 1804 int error = 0;
b78fb64d 1805 git_buf path = GIT_BUF_INIT;
1806
9462c471 1807 assert(repo && workdir);
602ee38b 1808
b78fb64d 1809 if (git_path_prettify_dir(&path, workdir, NULL) < 0)
1810 return -1;
9462c471 1811
991a56c7
RB
1812 if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0)
1813 return 0;
9462c471 1814
991a56c7
RB
1815 if (update_gitlink) {
1816 git_config *config;
1817
1818 if (git_repository_config__weakptr(&config, repo) < 0)
1819 return -1;
1820
bc737620 1821 error = repo_write_gitlink(path.ptr, git_repository_path(repo), false);
991a56c7
RB
1822
1823 /* passthrough error means gitlink is unnecessary */
1824 if (error == GIT_PASSTHROUGH)
54b2a37a 1825 error = git_config_delete_entry(config, "core.worktree");
991a56c7
RB
1826 else if (!error)
1827 error = git_config_set_string(config, "core.worktree", path.ptr);
1828
1829 if (!error)
1830 error = git_config_set_bool(config, "core.bare", false);
1831 }
1832
1833 if (!error) {
1834 char *old_workdir = repo->workdir;
1835
1836 repo->workdir = git_buf_detach(&path);
1837 repo->is_bare = 0;
1838
1839 git__free(old_workdir);
1840 }
1841
1842 return error;
4a34b3a9 1843}
fa9bcd81 1844
1845int git_repository_is_bare(git_repository *repo)
1846{
1847 assert(repo);
1848 return repo->is_bare;
1849}
f917481e 1850
1fbeb2f0
RB
1851int git_repository_set_bare(git_repository *repo)
1852{
1853 int error;
1854 git_config *config;
1855
1856 assert(repo);
1857
1858 if (repo->is_bare)
1859 return 0;
1860
74240afb
T
1861 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
1862 return error;
1863
b2a7bcdb 1864 if ((error = git_config_set_bool(config, "core.bare", true)) < 0)
74240afb 1865 return error;
1fbeb2f0 1866
74240afb
T
1867 if ((error = git_config__update_entry(config, "core.worktree", NULL, true, true)) < 0)
1868 return error;
1fbeb2f0
RB
1869
1870 git__free(repo->workdir);
1871 repo->workdir = NULL;
1fbeb2f0
RB
1872 repo->is_bare = 1;
1873
74240afb 1874 return 0;
1fbeb2f0
RB
1875}
1876
f917481e
RB
1877int git_repository_head_tree(git_tree **tree, git_repository *repo)
1878{
5cec896a 1879 git_reference *head;
1880 git_object *obj;
1881 int error;
f917481e 1882
5cec896a 1883 if ((error = git_repository_head(&head, repo)) < 0)
1884 return error;
f917481e 1885
5cec896a 1886 if ((error = git_reference_peel(&obj, head, GIT_OBJ_TREE)) < 0)
1887 goto cleanup;
f917481e
RB
1888
1889 *tree = (git_tree *)obj;
5cec896a 1890
1891cleanup:
1892 git_reference_free(head);
1893 return error;
f917481e 1894}
074841ec 1895
867a36f3
ET
1896int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head)
1897{
1898 git_filebuf file = GIT_FILEBUF_INIT;
1899 git_buf file_path = GIT_BUF_INIT;
1900 char orig_head_str[GIT_OID_HEXSZ];
1901 int error = 0;
1902
1903 git_oid_fmt(orig_head_str, orig_head);
1904
1905 if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 &&
1906 (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 &&
1907 (error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0)
1908 error = git_filebuf_commit(&file);
1909
1910 if (error < 0)
1911 git_filebuf_cleanup(&file);
1912
1913 git_buf_free(&file_path);
1914
1915 return error;
1916}
1917
3158e2fe 1918int git_repository_message(git_buf *out, git_repository *repo)
074841ec 1919{
7a3bd1e7 1920 git_buf path = GIT_BUF_INIT;
0ac349a9 1921 struct stat st;
0ac349a9 1922 int error;
074841ec 1923
7a3bd1e7 1924 git_buf_sanitize(out);
3d1c9f61 1925
632d8b23 1926 if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
0ac349a9 1927 return -1;
074841ec 1928
e9ca852e 1929 if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) {
074841ec
CMN
1930 if (errno == ENOENT)
1931 error = GIT_ENOTFOUND;
1a9e406c 1932 giterr_set(GITERR_OS, "Could not access message file");
3158e2fe
RB
1933 } else {
1934 error = git_futils_readbuffer(out, git_buf_cstr(&path));
0ac349a9 1935 }
074841ec 1936
7a3bd1e7 1937 git_buf_free(&path);
e9ca852e
RB
1938
1939 return error;
074841ec
CMN
1940}
1941
1942int git_repository_message_remove(git_repository *repo)
1943{
0ac349a9
VM
1944 git_buf path = GIT_BUF_INIT;
1945 int error;
074841ec 1946
632d8b23 1947 if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
0ac349a9 1948 return -1;
074841ec
CMN
1949
1950 error = p_unlink(git_buf_cstr(&path));
1951 git_buf_free(&path);
1952
1953 return error;
1954}
47bfa0be
RB
1955
1956int git_repository_hashfile(
0cb16fe9
L
1957 git_oid *out,
1958 git_repository *repo,
1959 const char *path,
1960 git_otype type,
1961 const char *as_path)
47bfa0be
RB
1962{
1963 int error;
85d54812 1964 git_filter_list *fl = NULL;
b1127a30 1965 git_file fd = -1;
47bfa0be
RB
1966 git_off_t len;
1967 git_buf full_path = GIT_BUF_INIT;
1968
a13fb55a
RB
1969 assert(out && path && repo); /* as_path can be NULL */
1970
1971 /* At some point, it would be nice if repo could be NULL to just
1972 * apply filter rules defined in system and global files, but for
1973 * now that is not possible because git_filters_load() needs it.
1974 */
47bfa0be
RB
1975
1976 error = git_path_join_unrooted(
526182d2 1977 &full_path, path, git_repository_workdir(repo), NULL);
47bfa0be
RB
1978 if (error < 0)
1979 return error;
1980
1981 if (!as_path)
1982 as_path = path;
1983
1984 /* passing empty string for "as_path" indicated --no-filters */
1985 if (strlen(as_path) > 0) {
4b11f25a 1986 error = git_filter_list_load(
5269008c 1987 &fl, repo, NULL, as_path,
795eaccd 1988 GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT);
47bfa0be
RB
1989 if (error < 0)
1990 return error;
1991 } else {
1992 error = 0;
1993 }
1994
1995 /* at this point, error is a count of the number of loaded filters */
1996
1997 fd = git_futils_open_ro(full_path.ptr);
1998 if (fd < 0) {
1999 error = fd;
2000 goto cleanup;
2001 }
2002
2003 len = git_futils_filesize(fd);
2004 if (len < 0) {
75050223 2005 error = (int)len;
47bfa0be
RB
2006 goto cleanup;
2007 }
2008
2009 if (!git__is_sizet(len)) {
2010 giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
2011 error = -1;
2012 goto cleanup;
2013 }
2014
85d54812 2015 error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, fl);
47bfa0be
RB
2016
2017cleanup:
b1127a30
SS
2018 if (fd >= 0)
2019 p_close(fd);
85d54812 2020 git_filter_list_free(fl);
47bfa0be
RB
2021 git_buf_free(&full_path);
2022
2023 return error;
2024}
2025
4e498646 2026static int checkout_message(git_buf *out, git_reference *old, const char *new)
44af67a8 2027{
4e498646
CMN
2028 git_buf_puts(out, "checkout: moving from ");
2029
2030 if (git_reference_type(old) == GIT_REF_SYMBOLIC)
2031 git_buf_puts(out, git_reference__shorthand(git_reference_symbolic_target(old)));
2032 else
2033 git_buf_puts(out, git_oid_tostr_s(git_reference_target(old)));
2034
2035 git_buf_puts(out, " to ");
2036
2037 if (git_reference__is_branch(new))
2038 git_buf_puts(out, git_reference__shorthand(new));
2039 else
2040 git_buf_puts(out, new);
2041
2042 if (git_buf_oom(out))
2043 return -1;
2044
2045 return 0;
44af67a8 2046}
2047
2048int git_repository_set_head(
2049 git_repository* repo,
4e498646 2050 const char* refname)
44af67a8 2051{
4e498646
CMN
2052 git_reference *ref = NULL, *current = NULL, *new_head = NULL;
2053 git_buf log_message = GIT_BUF_INIT;
44af67a8 2054 int error;
2055
2056 assert(repo && refname);
2057
4e498646
CMN
2058 if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
2059 return error;
2060
2061 if ((error = checkout_message(&log_message, current, refname)) < 0)
2062 goto cleanup;
2063
44af67a8 2064 error = git_reference_lookup(&ref, repo, refname);
2065 if (error < 0 && error != GIT_ENOTFOUND)
4e498646 2066 goto cleanup;
44af67a8 2067
2068 if (!error) {
94f263f5
BS
2069 if (git_reference_is_branch(ref)) {
2070 error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE,
4e498646 2071 git_reference_name(ref), true, git_buf_cstr(&log_message));
94f263f5 2072 } else {
4e498646 2073 error = git_repository_set_head_detached(repo, git_reference_target(ref));
94f263f5 2074 }
4e498646 2075 } else if (git_reference__is_branch(refname)) {
94f263f5 2076 error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname,
4e498646 2077 true, git_buf_cstr(&log_message));
94f263f5 2078 }
44af67a8 2079
4e498646 2080cleanup:
fe21d708 2081 git_buf_free(&log_message);
4e498646 2082 git_reference_free(current);
44af67a8 2083 git_reference_free(ref);
2084 git_reference_free(new_head);
2085 return error;
2086}
2087
62d38a1d 2088static int detach(git_repository *repo, const git_oid *id, const char *from)
4ebe38bd 2089{
2090 int error;
4e498646
CMN
2091 git_buf log_message = GIT_BUF_INIT;
2092 git_object *object = NULL, *peeled = NULL;
2093 git_reference *new_head = NULL, *current = NULL;
4ebe38bd 2094
62d38a1d 2095 assert(repo && id);
4ebe38bd 2096
4e498646 2097 if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
4ebe38bd 2098 return error;
2099
62d38a1d 2100 if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0)
4e498646
CMN
2101 goto cleanup;
2102
4ebe38bd 2103 if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0)
2104 goto cleanup;
2105
62d38a1d
CMN
2106 if (from == NULL)
2107 from = git_oid_tostr_s(git_object_id(peeled));
2108
2109 if ((error = checkout_message(&log_message, current, from)) < 0)
4e498646
CMN
2110 goto cleanup;
2111
2112 error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message));
4ebe38bd 2113
2114cleanup:
fe21d708 2115 git_buf_free(&log_message);
4ebe38bd 2116 git_object_free(object);
2117 git_object_free(peeled);
4e498646 2118 git_reference_free(current);
4ebe38bd 2119 git_reference_free(new_head);
2120 return error;
2121}
2122
62d38a1d
CMN
2123int git_repository_set_head_detached(
2124 git_repository* repo,
2125 const git_oid* commitish)
2126{
2127 return detach(repo, commitish, NULL);
2128}
2129
2130int git_repository_set_head_detached_from_annotated(
2131 git_repository *repo,
2132 const git_annotated_commit *commitish)
2133{
2134 assert(repo && commitish);
2135
2136 return detach(repo, git_annotated_commit_id(commitish), commitish->ref_name);
2137}
2138
4e498646 2139int git_repository_detach_head(git_repository* repo)
3f4c3072 2140{
4e498646 2141 git_reference *old_head = NULL, *new_head = NULL, *current = NULL;
3f4c3072 2142 git_object *object = NULL;
4e498646 2143 git_buf log_message = GIT_BUF_INIT;
8b05bea8 2144 int error;
3f4c3072 2145
2146 assert(repo);
2147
4e498646 2148 if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
8b05bea8 2149 return error;
3f4c3072 2150
4e498646
CMN
2151 if ((error = git_repository_head(&old_head, repo)) < 0)
2152 goto cleanup;
2153
2508cc66 2154 if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJ_COMMIT)) < 0)
3f4c3072 2155 goto cleanup;
2156
4e498646
CMN
2157 if ((error = checkout_message(&log_message, current, git_oid_tostr_s(git_object_id(object)))) < 0)
2158 goto cleanup;
2159
010cec3a 2160 error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head),
4e498646 2161 1, git_buf_cstr(&log_message));
3f4c3072 2162
2163cleanup:
fe21d708 2164 git_buf_free(&log_message);
3f4c3072 2165 git_object_free(object);
2166 git_reference_free(old_head);
2167 git_reference_free(new_head);
4e498646 2168 git_reference_free(current);
3f4c3072 2169 return error;
2170}
632d8b23 2171
31966d20 2172/**
2173 * Loosely ported from git.git
2174 * https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh#L198-289
2175 */
632d8b23
ET
2176int git_repository_state(git_repository *repo)
2177{
2178 git_buf repo_path = GIT_BUF_INIT;
2179 int state = GIT_REPOSITORY_STATE_NONE;
2180
2181 assert(repo);
2182
2183 if (git_buf_puts(&repo_path, repo->path_repository) < 0)
2184 return -1;
2185
31966d20 2186 if (git_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE))
2187 state = GIT_REPOSITORY_STATE_REBASE_INTERACTIVE;
2188 else if (git_path_contains_dir(&repo_path, GIT_REBASE_MERGE_DIR))
2189 state = GIT_REPOSITORY_STATE_REBASE_MERGE;
2190 else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_REBASING_FILE))
2191 state = GIT_REPOSITORY_STATE_REBASE;
2192 else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_APPLYING_FILE))
2193 state = GIT_REPOSITORY_STATE_APPLY_MAILBOX;
2194 else if (git_path_contains_dir(&repo_path, GIT_REBASE_APPLY_DIR))
2195 state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE;
2196 else if (git_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE))
632d8b23
ET
2197 state = GIT_REPOSITORY_STATE_MERGE;
2198 else if(git_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE))
2199 state = GIT_REPOSITORY_STATE_REVERT;
0ba4dca5
ET
2200 else if(git_path_contains_file(&repo_path, GIT_CHERRYPICK_HEAD_FILE))
2201 state = GIT_REPOSITORY_STATE_CHERRYPICK;
31966d20 2202 else if(git_path_contains_file(&repo_path, GIT_BISECT_LOG_FILE))
2203 state = GIT_REPOSITORY_STATE_BISECT;
632d8b23
ET
2204
2205 git_buf_free(&repo_path);
2206 return state;
2207}
93d8f77f 2208
c3dcbe84
VM
2209int git_repository__cleanup_files(
2210 git_repository *repo, const char *files[], size_t files_len)
bab0b9f2 2211{
c3dcbe84 2212 git_buf buf = GIT_BUF_INIT;
bab0b9f2 2213 size_t i;
c3dcbe84 2214 int error;
bab0b9f2 2215
c3dcbe84
VM
2216 for (error = 0, i = 0; !error && i < files_len; ++i) {
2217 const char *path;
bab0b9f2 2218
c3dcbe84
VM
2219 if (git_buf_joinpath(&buf, repo->path_repository, files[i]) < 0)
2220 return -1;
bab0b9f2 2221
c3dcbe84
VM
2222 path = git_buf_cstr(&buf);
2223
2224 if (git_path_isfile(path)) {
2225 error = p_unlink(path);
2226 } else if (git_path_isdir(path)) {
2227 error = git_futils_rmdir_r(path, NULL,
2228 GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS);
2229 }
2230
2231 git_buf_clear(&buf);
2232 }
bab0b9f2 2233
c3dcbe84 2234 git_buf_free(&buf);
bab0b9f2
ET
2235 return error;
2236}
2237
2238static const char *state_files[] = {
2239 GIT_MERGE_HEAD_FILE,
2240 GIT_MERGE_MODE_FILE,
2241 GIT_MERGE_MSG_FILE,
2242 GIT_REVERT_HEAD_FILE,
0ba4dca5 2243 GIT_CHERRYPICK_HEAD_FILE,
c0311295
JG
2244 GIT_BISECT_LOG_FILE,
2245 GIT_REBASE_MERGE_DIR,
2246 GIT_REBASE_APPLY_DIR,
bab0b9f2
ET
2247};
2248
2249int git_repository_state_cleanup(git_repository *repo)
2250{
2251 assert(repo);
2252
2253 return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
2254}
2255
93d8f77f
BS
2256int git_repository_is_shallow(git_repository *repo)
2257{
2258 git_buf path = GIT_BUF_INIT;
2259 struct stat st;
6f0b8142 2260 int error;
93d8f77f 2261
3dbd9a0e
JG
2262 if ((error = git_buf_joinpath(&path, repo->path_repository, "shallow")) < 0)
2263 return error;
2264
6f0b8142
BS
2265 error = git_path_lstat(path.ptr, &st);
2266 git_buf_free(&path);
93d8f77f 2267
9bda5fb8
BS
2268 if (error == GIT_ENOTFOUND) {
2269 giterr_clear();
93d8f77f 2270 return 0;
9bda5fb8
BS
2271 }
2272
864535cf
BS
2273 if (error < 0)
2274 return error;
2275 return st.st_size == 0 ? 0 : 1;
93d8f77f 2276}
b9f81997 2277
702efc89
RB
2278int git_repository_init_init_options(
2279 git_repository_init_options *opts, unsigned int version)
b9f81997 2280{
702efc89
RB
2281 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2282 opts, version, git_repository_init_options,
2283 GIT_REPOSITORY_INIT_OPTIONS_INIT);
2284 return 0;
b9f81997 2285}
659cf202
CMN
2286
2287int git_repository_ident(const char **name, const char **email, const git_repository *repo)
2288{
2289 *name = repo->ident_name;
2290 *email = repo->ident_email;
2291
2292 return 0;
2293}
2294
2295int git_repository_set_ident(git_repository *repo, const char *name, const char *email)
2296{
2297 char *tmp_name = NULL, *tmp_email = NULL;
2298
2299 if (name) {
2300 tmp_name = git__strdup(name);
2301 GITERR_CHECK_ALLOC(tmp_name);
2302 }
2303
2304 if (email) {
2305 tmp_email = git__strdup(email);
2306 GITERR_CHECK_ALLOC(tmp_email);
2307 }
2308
2309 tmp_name = git__swap(repo->ident_name, tmp_name);
2310 tmp_email = git__swap(repo->ident_email, tmp_email);
2311
2312 git__free(tmp_name);
2313 git__free(tmp_email);
2314
2315 return 0;
2316}