]> git.proxmox.com Git - libgit2.git/blame - src/repository.c
rebase::abort: test we can abort rebase by revspec
[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,
8c7c5fa5
CMN
588 const char *system_config_path,
589 const char *programdata_path)
b22d1479 590{
cc6b4162 591 int error;
97769280 592 git_buf config_path = GIT_BUF_INIT;
9462c471 593 git_config *cfg = NULL;
b22d1479 594
9462c471 595 assert(repo && out);
07ff8817 596
cc6b4162
RB
597 if ((error = git_config_new(&cfg)) < 0)
598 return error;
b22d1479 599
cc6b4162
RB
600 error = git_buf_joinpath(
601 &config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO);
602 if (error < 0)
cb8a7961 603 goto on_error;
97769280 604
cc6b4162
RB
605 if ((error = git_config_add_file_ondisk(
606 cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0 &&
607 error != GIT_ENOTFOUND)
cb8a7961
VM
608 goto on_error;
609
610 git_buf_free(&config_path);
b22d1479 611
cc6b4162
RB
612 if (global_config_path != NULL &&
613 (error = git_config_add_file_ondisk(
614 cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, 0)) < 0 &&
615 error != GIT_ENOTFOUND)
616 goto on_error;
8b4f9b17 617
cc6b4162
RB
618 if (xdg_config_path != NULL &&
619 (error = git_config_add_file_ondisk(
620 cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, 0)) < 0 &&
621 error != GIT_ENOTFOUND)
622 goto on_error;
b22d1479 623
cc6b4162
RB
624 if (system_config_path != NULL &&
625 (error = git_config_add_file_ondisk(
626 cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, 0)) < 0 &&
627 error != GIT_ENOTFOUND)
628 goto on_error;
9ba9e513 629
8c7c5fa5
CMN
630 if (programdata_path != NULL &&
631 (error = git_config_add_file_ondisk(
632 cfg, programdata_path, GIT_CONFIG_LEVEL_PROGRAMDATA, 0)) < 0 &&
633 error != GIT_ENOTFOUND)
634 goto on_error;
635
38f7d026
RB
636 giterr_clear(); /* clear any lingering ENOTFOUND errors */
637
9462c471 638 *out = cfg;
cb8a7961 639 return 0;
b22d1479 640
cb8a7961
VM
641on_error:
642 git_buf_free(&config_path);
9462c471
VM
643 git_config_free(cfg);
644 *out = NULL;
cc6b4162 645 return error;
b22d1479
CMN
646}
647
53607868 648static const char *path_unless_empty(git_buf *buf)
40fe5fbe 649{
53607868
RB
650 return git_buf_len(buf) > 0 ? git_buf_cstr(buf) : NULL;
651}
8b4f9b17 652
53607868
RB
653int git_repository_config__weakptr(git_config **out, git_repository *repo)
654{
655 int error = 0;
40fe5fbe 656
53607868
RB
657 if (repo->_config == NULL) {
658 git_buf global_buf = GIT_BUF_INIT;
659 git_buf xdg_buf = GIT_BUF_INIT;
660 git_buf system_buf = GIT_BUF_INIT;
8c7c5fa5 661 git_buf programdata_buf = GIT_BUF_INIT;
53607868
RB
662 git_config *config;
663
ee550477
CMN
664 git_config_find_global(&global_buf);
665 git_config_find_xdg(&xdg_buf);
666 git_config_find_system(&system_buf);
8c7c5fa5 667 git_config_find_programdata(&programdata_buf);
53607868 668
a4b75dcf
CMN
669 /* If there is no global file, open a backend for it anyway */
670 if (git_buf_len(&global_buf) == 0)
671 git_config__global_location(&global_buf);
672
53607868
RB
673 error = load_config(
674 &config, repo,
675 path_unless_empty(&global_buf),
676 path_unless_empty(&xdg_buf),
8c7c5fa5
CMN
677 path_unless_empty(&system_buf),
678 path_unless_empty(&programdata_buf));
53607868
RB
679 if (!error) {
680 GIT_REFCOUNT_OWN(config, repo);
681
e976b56d 682 config = git__compare_and_swap(&repo->_config, NULL, config);
53607868
RB
683 if (config != NULL) {
684 GIT_REFCOUNT_OWN(config, NULL);
685 git_config_free(config);
686 }
687 }
97769280
RB
688
689 git_buf_free(&global_buf);
a8918418 690 git_buf_free(&xdg_buf);
97769280 691 git_buf_free(&system_buf);
4f971852 692 git_buf_free(&programdata_buf);
9462c471 693 }
40fe5fbe 694
9462c471 695 *out = repo->_config;
53607868 696 return error;
40fe5fbe
CMN
697}
698
9462c471 699int git_repository_config(git_config **out, git_repository *repo)
fd0574e5 700{
cb8a7961
VM
701 if (git_repository_config__weakptr(out, repo) < 0)
702 return -1;
fd0574e5 703
cb8a7961
VM
704 GIT_REFCOUNT_INC(*out);
705 return 0;
9462c471
VM
706}
707
ac99d86b
CMN
708int git_repository_config_snapshot(git_config **out, git_repository *repo)
709{
b1914c36 710 int error;
ac99d86b
CMN
711 git_config *weak;
712
b1914c36
RB
713 if ((error = git_repository_config__weakptr(&weak, repo)) < 0)
714 return error;
ac99d86b
CMN
715
716 return git_config_snapshot(out, weak);
717}
718
9462c471
VM
719void git_repository_set_config(git_repository *repo, git_config *config)
720{
721 assert(repo && config);
e976b56d 722 set_config(repo, config);
9462c471
VM
723}
724
725int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
726{
53607868
RB
727 int error = 0;
728
9462c471
VM
729 assert(repo && out);
730
731 if (repo->_odb == NULL) {
97769280 732 git_buf odb_path = GIT_BUF_INIT;
53607868 733 git_odb *odb;
9462c471 734
3dbd9a0e
JG
735 if ((error = git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR)) < 0)
736 return error;
9462c471 737
53607868
RB
738 error = git_odb_open(&odb, odb_path.ptr);
739 if (!error) {
740 GIT_REFCOUNT_OWN(odb, repo);
cb8a7961 741
e976b56d 742 odb = git__compare_and_swap(&repo->_odb, NULL, odb);
53607868
RB
743 if (odb != NULL) {
744 GIT_REFCOUNT_OWN(odb, NULL);
745 git_odb_free(odb);
746 }
747 }
9462c471 748
53607868 749 git_buf_free(&odb_path);
9462c471 750 }
fd0574e5 751
9462c471 752 *out = repo->_odb;
53607868 753 return error;
fd0574e5
RG
754}
755
9462c471 756int git_repository_odb(git_odb **out, git_repository *repo)
6fd195d7 757{
cb8a7961
VM
758 if (git_repository_odb__weakptr(out, repo) < 0)
759 return -1;
1795f879 760
cb8a7961
VM
761 GIT_REFCOUNT_INC(*out);
762 return 0;
9462c471 763}
6fd195d7 764
9462c471
VM
765void git_repository_set_odb(git_repository *repo, git_odb *odb)
766{
767 assert(repo && odb);
e976b56d 768 set_odb(repo, odb);
9462c471
VM
769}
770
d00d5464
ET
771int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo)
772{
53607868
RB
773 int error = 0;
774
d00d5464
ET
775 assert(out && repo);
776
777 if (repo->_refdb == NULL) {
53607868 778 git_refdb *refdb;
d00d5464 779
53607868
RB
780 error = git_refdb_open(&refdb, repo);
781 if (!error) {
782 GIT_REFCOUNT_OWN(refdb, repo);
d00d5464 783
e976b56d 784 refdb = git__compare_and_swap(&repo->_refdb, NULL, refdb);
53607868
RB
785 if (refdb != NULL) {
786 GIT_REFCOUNT_OWN(refdb, NULL);
787 git_refdb_free(refdb);
788 }
789 }
d00d5464
ET
790 }
791
792 *out = repo->_refdb;
53607868 793 return error;
d00d5464
ET
794}
795
796int git_repository_refdb(git_refdb **out, git_repository *repo)
797{
798 if (git_repository_refdb__weakptr(out, repo) < 0)
799 return -1;
800
801 GIT_REFCOUNT_INC(*out);
802 return 0;
803}
804
805void git_repository_set_refdb(git_repository *repo, git_refdb *refdb)
806{
53607868 807 assert(repo && refdb);
e976b56d 808 set_refdb(repo, refdb);
d00d5464
ET
809}
810
9462c471
VM
811int git_repository_index__weakptr(git_index **out, git_repository *repo)
812{
53607868
RB
813 int error = 0;
814
9462c471
VM
815 assert(out && repo);
816
9462c471 817 if (repo->_index == NULL) {
97769280 818 git_buf index_path = GIT_BUF_INIT;
53607868 819 git_index *index;
9462c471 820
3dbd9a0e
JG
821 if ((error = git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE)) < 0)
822 return error;
9462c471 823
53607868
RB
824 error = git_index_open(&index, index_path.ptr);
825 if (!error) {
826 GIT_REFCOUNT_OWN(index, repo);
cb8a7961 827
e976b56d 828 index = git__compare_and_swap(&repo->_index, NULL, index);
53607868
RB
829 if (index != NULL) {
830 GIT_REFCOUNT_OWN(index, NULL);
831 git_index_free(index);
832 }
9462c471 833
53607868
RB
834 error = git_index_set_caps(repo->_index, GIT_INDEXCAP_FROM_OWNER);
835 }
da825c92 836
53607868 837 git_buf_free(&index_path);
9462c471
VM
838 }
839
9462c471 840 *out = repo->_index;
53607868 841 return error;
9462c471 842}
1795f879 843
9462c471
VM
844int git_repository_index(git_index **out, git_repository *repo)
845{
cb8a7961
VM
846 if (git_repository_index__weakptr(out, repo) < 0)
847 return -1;
9462c471 848
cb8a7961
VM
849 GIT_REFCOUNT_INC(*out);
850 return 0;
3315782c
VM
851}
852
9462c471
VM
853void git_repository_set_index(git_repository *repo, git_index *index)
854{
fa8ca519 855 assert(repo);
e976b56d 856 set_index(repo, index);
9462c471
VM
857}
858
bade5194
VM
859int git_repository_set_namespace(git_repository *repo, const char *namespace)
860{
861 git__free(repo->namespace);
862
863 if (namespace == NULL) {
864 repo->namespace = NULL;
865 return 0;
866 }
867
868 return (repo->namespace = git__strdup(namespace)) ? 0 : -1;
869}
870
871const char *git_repository_get_namespace(git_repository *repo)
872{
873 return repo->namespace;
874}
875
4196dd8e
ET
876#ifdef GIT_WIN32
877static int reserved_names_add8dot3(git_repository *repo, const char *path)
a64119e3 878{
4196dd8e
ET
879 char *name = git_win32_path_8dot3_name(path);
880 const char *def = GIT_DIR_SHORTNAME;
526f91f5 881 const char *def_dot_git = DOT_GIT;
4196dd8e 882 size_t name_len, def_len = CONST_STRLEN(GIT_DIR_SHORTNAME);
526f91f5 883 size_t def_dot_git_len = CONST_STRLEN(DOT_GIT);
4196dd8e 884 git_buf *buf;
a64119e3 885
4196dd8e
ET
886 if (!name)
887 return 0;
888
889 name_len = strlen(name);
890
526f91f5
L
891 if ((name_len == def_len && memcmp(name, def, def_len) == 0) ||
892 (name_len == def_dot_git_len && memcmp(name, def_dot_git, def_dot_git_len) == 0)) {
4196dd8e
ET
893 git__free(name);
894 return 0;
895 }
896
897 if ((buf = git_array_alloc(repo->reserved_names)) == NULL)
898 return -1;
899
900 git_buf_attach(buf, name, name_len);
901 return true;
902}
903
904bool git_repository__reserved_names(
905 git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs)
906{
907 GIT_UNUSED(include_ntfs);
908
909 if (repo->reserved_names.size == 0) {
910 git_buf *buf;
911 size_t i;
912
913 /* Add the static defaults */
914 for (i = 0; i < git_repository__reserved_names_win32_len; i++) {
915 if ((buf = git_array_alloc(repo->reserved_names)) == NULL)
916 goto on_error;
917
918 buf->ptr = git_repository__reserved_names_win32[i].ptr;
919 buf->size = git_repository__reserved_names_win32[i].size;
920 }
921
538dfc88
ET
922 /* Try to add any repo-specific reserved names - the gitlink file
923 * within a submodule or the repository (if the repository directory
924 * is beneath the workdir). These are typically `.git`, but should
925 * be protected in case they are not. Note, repo and workdir paths
926 * are always prettified to end in `/`, so a prefixcmp is safe.
927 */
a64119e3 928 if (!repo->is_bare) {
538dfc88
ET
929 int (*prefixcmp)(const char *, const char *);
930 int error, ignorecase;
a64119e3 931
538dfc88
ET
932 error = git_repository__cvar(
933 &ignorecase, repo, GIT_CVAR_IGNORECASE);
934 prefixcmp = (error || ignorecase) ? git__prefixcmp_icase :
935 git__prefixcmp;
936
937 if (repo->path_gitlink &&
938 reserved_names_add8dot3(repo, repo->path_gitlink) < 0)
939 goto on_error;
940
941 if (repo->path_repository &&
942 prefixcmp(repo->path_repository, repo->workdir) == 0 &&
943 reserved_names_add8dot3(repo, repo->path_repository) < 0)
4196dd8e 944 goto on_error;
a64119e3 945 }
a64119e3
ET
946 }
947
4196dd8e
ET
948 *out = repo->reserved_names.ptr;
949 *outlen = repo->reserved_names.size;
950
951 return true;
952
953 /* Always give good defaults, even on OOM */
954on_error:
955 *out = git_repository__reserved_names_win32;
956 *outlen = git_repository__reserved_names_win32_len;
957
958 return false;
a64119e3 959}
4196dd8e
ET
960#else
961bool git_repository__reserved_names(
962 git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs)
963{
964 GIT_UNUSED(repo);
965
966 if (include_ntfs) {
967 *out = git_repository__reserved_names_win32;
968 *outlen = git_repository__reserved_names_win32_len;
969 } else {
970 *out = git_repository__reserved_names_posix;
971 *outlen = git_repository__reserved_names_posix_len;
972 }
973
974 return true;
975}
976#endif
a64119e3 977
2c227b8b 978static int check_repositoryformatversion(git_config *config)
40c44d2f 979{
99e11cdd 980 int version, error;
5663e61a 981
99e11cdd
CMN
982 error = git_config_get_int32(&version, config, "core.repositoryformatversion");
983 /* git ignores this if the config variable isn't there */
984 if (error == GIT_ENOTFOUND)
985 return 0;
986
987 if (error < 0)
cb8a7961 988 return -1;
5663e61a 989
29e948de 990 if (GIT_REPO_VERSION < version) {
cb8a7961
VM
991 giterr_set(GITERR_REPOSITORY,
992 "Unsupported repository version %d. Only versions up to %d are supported.",
29e948de 993 version, GIT_REPO_VERSION);
cb8a7961
VM
994 return -1;
995 }
5663e61a 996
cb8a7961 997 return 0;
5663e61a 998}
999
662880ca 1000static int repo_init_create_head(const char *git_dir, const char *ref_name)
e1f8cad0 1001{
97769280 1002 git_buf ref_path = GIT_BUF_INIT;
9462c471 1003 git_filebuf ref = GIT_FILEBUF_INIT;
662880ca 1004 const char *fmt;
9462c471 1005
cb8a7961 1006 if (git_buf_joinpath(&ref_path, git_dir, GIT_HEAD_FILE) < 0 ||
1d3a8aeb 1007 git_filebuf_open(&ref, ref_path.ptr, 0, GIT_REFS_FILE_MODE) < 0)
662880ca
RB
1008 goto fail;
1009
1010 if (!ref_name)
1011 ref_name = GIT_BRANCH_MASTER;
1012
74a24005 1013 if (git__prefixcmp(ref_name, GIT_REFS_DIR) == 0)
662880ca
RB
1014 fmt = "ref: %s\n";
1015 else
74a24005 1016 fmt = "ref: " GIT_REFS_HEADS_DIR "%s\n";
662880ca
RB
1017
1018 if (git_filebuf_printf(&ref, fmt, ref_name) < 0 ||
1d3a8aeb 1019 git_filebuf_commit(&ref) < 0)
662880ca 1020 goto fail;
9462c471 1021
97769280 1022 git_buf_free(&ref_path);
cb8a7961 1023 return 0;
662880ca
RB
1024
1025fail:
1026 git_buf_free(&ref_path);
1027 git_filebuf_cleanup(&ref);
1028 return -1;
9462c471
VM
1029}
1030
fac66990 1031static bool is_chmod_supported(const char *file_path)
1032{
1033 struct stat st1, st2;
fac66990 1034
1035 if (p_stat(file_path, &st1) < 0)
1036 return false;
1037
1038 if (p_chmod(file_path, st1.st_mode ^ S_IXUSR) < 0)
1039 return false;
1040
1041 if (p_stat(file_path, &st2) < 0)
1042 return false;
1043
6b7991e2 1044 return (st1.st_mode != st2.st_mode);
fac66990 1045}
1046
693b23c0 1047static bool is_filesystem_case_insensitive(const char *gitdir_path)
1048{
1049 git_buf path = GIT_BUF_INIT;
6b7991e2 1050 int is_insensitive = -1;
693b23c0 1051
6b7991e2
RB
1052 if (!git_buf_joinpath(&path, gitdir_path, "CoNfIg"))
1053 is_insensitive = git_path_exists(git_buf_cstr(&path));
693b23c0 1054
693b23c0 1055 git_buf_free(&path);
6b7991e2 1056 return is_insensitive;
693b23c0 1057}
1058
ca1b6e54
RB
1059static bool are_symlinks_supported(const char *wd_path)
1060{
1061 git_buf path = GIT_BUF_INIT;
1062 int fd;
1063 struct stat st;
6b7991e2 1064 int symlinks_supported = -1;
ca1b6e54 1065
1d3a8aeb 1066 if ((fd = git_futils_mktmp(&path, wd_path, 0666)) < 0 ||
ca1b6e54
RB
1067 p_close(fd) < 0 ||
1068 p_unlink(path.ptr) < 0 ||
1069 p_symlink("testing", path.ptr) < 0 ||
1070 p_lstat(path.ptr, &st) < 0)
6b7991e2 1071 symlinks_supported = false;
ca1b6e54 1072 else
6b7991e2 1073 symlinks_supported = (S_ISLNK(st.st_mode) != 0);
ca1b6e54
RB
1074
1075 (void)p_unlink(path.ptr);
1076 git_buf_free(&path);
1077
6b7991e2
RB
1078 return symlinks_supported;
1079}
1080
270160b9 1081static int create_empty_file(const char *path, mode_t mode)
1082{
1083 int fd;
1084
1085 if ((fd = p_creat(path, mode)) < 0) {
1086 giterr_set(GITERR_OS, "Error while creating '%s'", path);
1087 return -1;
1088 }
1089
1090 if (p_close(fd) < 0) {
1091 giterr_set(GITERR_OS, "Error while closing '%s'", path);
1092 return -1;
1093 }
1094
1095 return 0;
1096}
1097
14997dc5
RB
1098static int repo_local_config(
1099 git_config **out,
1100 git_buf *config_dir,
1101 git_repository *repo,
1102 const char *repo_dir)
9462c471 1103{
ca1b6e54 1104 int error = 0;
14997dc5
RB
1105 git_config *parent;
1106 const char *cfg_path;
9462c471 1107
14997dc5 1108 if (git_buf_joinpath(config_dir, repo_dir, GIT_CONFIG_FILENAME_INREPO) < 0)
cb8a7961 1109 return -1;
14997dc5 1110 cfg_path = git_buf_cstr(config_dir);
9462c471 1111
14997dc5 1112 /* make LOCAL config if missing */
5173ea92
RB
1113 if (!git_path_isfile(cfg_path) &&
1114 (error = create_empty_file(cfg_path, GIT_CONFIG_FILE_MODE)) < 0)
14997dc5 1115 return error;
270160b9 1116
14997dc5
RB
1117 /* if no repo, just open that file directly */
1118 if (!repo)
1119 return git_config_open_ondisk(out, cfg_path);
1120
1121 /* otherwise, open parent config and get that level */
1122 if ((error = git_repository_config__weakptr(&parent, repo)) < 0)
1123 return error;
1124
1125 if (git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL) < 0) {
5173ea92
RB
1126 giterr_clear();
1127
1128 if (!(error = git_config_add_file_ondisk(
1129 parent, cfg_path, GIT_CONFIG_LEVEL_LOCAL, false)))
14997dc5 1130 error = git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL);
cb8a7961 1131 }
9462c471 1132
14997dc5
RB
1133 git_config_free(parent);
1134
1135 return error;
1136}
1137
1138static int repo_init_fs_configs(
1139 git_config *cfg,
1140 const char *cfg_path,
1141 const char *repo_dir,
1142 const char *work_dir,
1143 bool update_ignorecase)
1144{
1145 int error = 0;
1146
1147 if (!work_dir)
1148 work_dir = repo_dir;
1149
1150 if ((error = git_config_set_bool(
1151 cfg, "core.filemode", is_chmod_supported(cfg_path))) < 0)
1152 return error;
1153
1154 if (!are_symlinks_supported(work_dir)) {
1155 if ((error = git_config_set_bool(cfg, "core.symlinks", false)) < 0)
1156 return error;
1157 } else if (git_config_delete_entry(cfg, "core.symlinks") < 0)
1158 giterr_clear();
2c227b8b 1159
14997dc5
RB
1160 if (update_ignorecase) {
1161 if (is_filesystem_case_insensitive(repo_dir)) {
1162 if ((error = git_config_set_bool(cfg, "core.ignorecase", true)) < 0)
1163 return error;
1164 } else if (git_config_delete_entry(cfg, "core.ignorecase") < 0)
1165 giterr_clear();
1166 }
662880ca 1167
af302aca 1168#ifdef GIT_USE_ICONV
14997dc5
RB
1169 if ((error = git_config_set_bool(
1170 cfg, "core.precomposeunicode",
43a04135 1171 git_path_does_fs_decompose_unicode(work_dir))) < 0)
14997dc5 1172 return error;
43a04135 1173 /* on non-iconv platforms, don't even set core.precomposeunicode */
6b7991e2
RB
1174#endif
1175
14997dc5
RB
1176 return 0;
1177}
7623b1b6 1178
14997dc5
RB
1179static int repo_init_config(
1180 const char *repo_dir,
1181 const char *work_dir,
1182 uint32_t flags,
1183 uint32_t mode)
1184{
1185 int error = 0;
bc737620 1186 git_buf cfg_path = GIT_BUF_INIT, worktree_path = GIT_BUF_INIT;
14997dc5
RB
1187 git_config *config = NULL;
1188 bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
1189 bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
1190
1191 if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0)
1192 goto cleanup;
1193
1194 if (is_reinit && (error = check_repositoryformatversion(config)) < 0)
1195 goto cleanup;
1196
1197#define SET_REPO_CONFIG(TYPE, NAME, VAL) do { \
1198 if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \
1199 goto cleanup; } while (0)
1200
1201 SET_REPO_CONFIG(bool, "core.bare", is_bare);
1202 SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION);
1203
1204 if ((error = repo_init_fs_configs(
1205 config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0)
1206 goto cleanup;
5173ea92 1207
6b7991e2
RB
1208 if (!is_bare) {
1209 SET_REPO_CONFIG(bool, "core.logallrefupdates", true);
ca1b6e54 1210
bc737620
JM
1211 if (!(flags & GIT_REPOSITORY_INIT__NATURAL_WD)) {
1212 if ((error = git_buf_sets(&worktree_path, work_dir)) < 0)
1213 goto cleanup;
1214
1215 if ((flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK))
1216 if ((error = git_path_make_relative(&worktree_path, repo_dir)) < 0)
1217 goto cleanup;
1218
1219 SET_REPO_CONFIG(string, "core.worktree", worktree_path.ptr);
1220 } else if (is_reinit) {
54b2a37a 1221 if (git_config_delete_entry(config, "core.worktree") < 0)
89cd5708 1222 giterr_clear();
ca1b6e54 1223 }
ca1b6e54
RB
1224 }
1225
5173ea92 1226 if (mode == GIT_REPOSITORY_INIT_SHARED_GROUP) {
662880ca
RB
1227 SET_REPO_CONFIG(int32, "core.sharedrepository", 1);
1228 SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true);
ca1b6e54 1229 }
5173ea92 1230 else if (mode == GIT_REPOSITORY_INIT_SHARED_ALL) {
662880ca
RB
1231 SET_REPO_CONFIG(int32, "core.sharedrepository", 2);
1232 SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true);
1233 }
9462c471 1234
ca1b6e54 1235cleanup:
14997dc5 1236 git_buf_free(&cfg_path);
bc737620 1237 git_buf_free(&worktree_path);
9462c471 1238 git_config_free(config);
662880ca 1239
ca1b6e54 1240 return error;
d2d6912e 1241}
e1f8cad0 1242
867f7c9b 1243static int repo_reinit_submodule_fs(git_submodule *sm, const char *n, void *p)
5173ea92 1244{
14997dc5
RB
1245 git_repository *smrepo = NULL;
1246 GIT_UNUSED(n); GIT_UNUSED(p);
5173ea92 1247
14997dc5 1248 if (git_submodule_open(&smrepo, sm) < 0 ||
867f7c9b 1249 git_repository_reinit_filesystem(smrepo, true) < 0)
14997dc5
RB
1250 giterr_clear();
1251 git_repository_free(smrepo);
5173ea92 1252
14997dc5
RB
1253 return 0;
1254}
5173ea92 1255
867f7c9b 1256int git_repository_reinit_filesystem(git_repository *repo, int recurse)
14997dc5
RB
1257{
1258 int error = 0;
1259 git_buf path = GIT_BUF_INIT;
1260 git_config *config = NULL;
1261 const char *repo_dir = git_repository_path(repo);
5173ea92 1262
14997dc5
RB
1263 if (!(error = repo_local_config(&config, &path, repo, repo_dir)))
1264 error = repo_init_fs_configs(
1265 config, path.ptr, repo_dir, git_repository_workdir(repo), true);
5173ea92 1266
14997dc5
RB
1267 git_config_free(config);
1268 git_buf_free(&path);
5173ea92 1269
5173ea92
RB
1270 git_repository__cvar_cache_clear(repo);
1271
14997dc5 1272 if (!repo->is_bare && recurse)
867f7c9b 1273 (void)git_submodule_foreach(repo, repo_reinit_submodule_fs, NULL);
14997dc5 1274
5173ea92
RB
1275 return error;
1276}
1277
dc34da6e 1278static int repo_write_template(
991a56c7
RB
1279 const char *git_dir,
1280 bool allow_overwrite,
1281 const char *file,
1282 mode_t mode,
662880ca 1283 bool hidden,
991a56c7 1284 const char *content)
dc34da6e
RB
1285{
1286 git_buf path = GIT_BUF_INIT;
991a56c7 1287 int fd, error = 0, flags;
dc34da6e
RB
1288
1289 if (git_buf_joinpath(&path, git_dir, file) < 0)
1290 return -1;
1291
991a56c7
RB
1292 if (allow_overwrite)
1293 flags = O_WRONLY | O_CREAT | O_TRUNC;
1294 else
1295 flags = O_WRONLY | O_CREAT | O_EXCL;
1296
1297 fd = p_open(git_buf_cstr(&path), flags, mode);
dc34da6e 1298
db628072
RB
1299 if (fd >= 0) {
1300 error = p_write(fd, content, strlen(content));
dc34da6e 1301
db628072
RB
1302 p_close(fd);
1303 }
1304 else if (errno != EEXIST)
1305 error = fd;
dc34da6e 1306
662880ca
RB
1307#ifdef GIT_WIN32
1308 if (!error && hidden) {
bdec3363 1309 if (git_win32__set_hidden(path.ptr, true) < 0)
662880ca
RB
1310 error = -1;
1311 }
1312#else
1313 GIT_UNUSED(hidden);
1314#endif
1315
dc34da6e 1316 git_buf_free(&path);
db628072
RB
1317
1318 if (error)
1319 giterr_set(GITERR_OS,
1320 "Failed to initialize repository with template '%s'", file);
1321
1322 return error;
dc34da6e
RB
1323}
1324
662880ca 1325static int repo_write_gitlink(
bc737620 1326 const char *in_dir, const char *to_repo, bool use_relative_path)
4b8e27c8 1327{
662880ca
RB
1328 int error;
1329 git_buf buf = GIT_BUF_INIT;
bc737620 1330 git_buf path_to_repo = GIT_BUF_INIT;
662880ca
RB
1331 struct stat st;
1332
1333 git_path_dirname_r(&buf, to_repo);
1334 git_path_to_dir(&buf);
1335 if (git_buf_oom(&buf))
cb8a7961 1336 return -1;
a67a096a 1337
662880ca
RB
1338 /* don't write gitlink to natural workdir */
1339 if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 &&
1340 strcmp(in_dir, buf.ptr) == 0)
1341 {
1342 error = GIT_PASSTHROUGH;
1343 goto cleanup;
1344 }
1345
1346 if ((error = git_buf_joinpath(&buf, in_dir, DOT_GIT)) < 0)
1347 goto cleanup;
1348
1349 if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) {
1350 giterr_set(GITERR_REPOSITORY,
1351 "Cannot overwrite gitlink file into path '%s'", in_dir);
1352 error = GIT_EEXISTS;
1353 goto cleanup;
1354 }
1355
1356 git_buf_clear(&buf);
1357
bc737620
JM
1358 error = git_buf_sets(&path_to_repo, to_repo);
1359
1360 if (!error && use_relative_path)
1361 error = git_path_make_relative(&path_to_repo, in_dir);
1362
1363 if (!error)
1364 error = git_buf_join(&buf, ' ', GIT_FILE_CONTENT_PREFIX, path_to_repo.ptr);
662880ca
RB
1365
1366 if (!error)
18f08264 1367 error = repo_write_template(in_dir, true, DOT_GIT, 0666, true, buf.ptr);
662880ca
RB
1368
1369cleanup:
1370 git_buf_free(&buf);
bc737620 1371 git_buf_free(&path_to_repo);
662880ca
RB
1372 return error;
1373}
1374
ca1b6e54
RB
1375static mode_t pick_dir_mode(git_repository_init_options *opts)
1376{
1377 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_UMASK)
18f08264 1378 return 0777;
ca1b6e54
RB
1379 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_GROUP)
1380 return (0775 | S_ISGID);
1381 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_ALL)
1382 return (0777 | S_ISGID);
1383 return opts->mode;
1384}
1385
662880ca
RB
1386#include "repo_template.h"
1387
1388static int repo_init_structure(
1389 const char *repo_dir,
1390 const char *work_dir,
1391 git_repository_init_options *opts)
1392{
ca1b6e54 1393 int error = 0;
662880ca 1394 repo_template_item *tpl;
ca1b6e54
RB
1395 bool external_tpl =
1396 ((opts->flags & GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) != 0);
1397 mode_t dmode = pick_dir_mode(opts);
bafaf790 1398 bool chmod = opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK;
662880ca
RB
1399
1400 /* Hide the ".git" directory */
17837602 1401#ifdef GIT_WIN32
2eb4edf5 1402 if ((opts->flags & GIT_REPOSITORY_INIT__HAS_DOTGIT) != 0) {
bdec3363 1403 if (git_win32__set_hidden(repo_dir, true) < 0) {
c2c81615 1404 giterr_set(GITERR_OS,
cb8a7961
VM
1405 "Failed to mark Git repository folder as hidden");
1406 return -1;
1407 }
17837602 1408 }
2eb4edf5
RB
1409#endif
1410
1411 /* Create the .git gitlink if appropriate */
1412 if ((opts->flags & GIT_REPOSITORY_INIT_BARE) == 0 &&
1413 (opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD) == 0)
1414 {
bc737620 1415 if (repo_write_gitlink(work_dir, repo_dir, opts->flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK) < 0)
cb8a7961 1416 return -1;
97769280 1417 }
1c2c7c0d 1418
ca1b6e54
RB
1419 /* Copy external template if requested */
1420 if (external_tpl) {
0cd1c3bb
L
1421 git_config *cfg = NULL;
1422 const char *tdir = NULL;
1423 bool default_template = false;
a025907e
L
1424 git_buf template_buf = GIT_BUF_INIT;
1425
ca1b6e54
RB
1426 if (opts->template_path)
1427 tdir = opts->template_path;
0cd1c3bb 1428 else if ((error = git_config_open_default(&cfg)) >= 0) {
cc36f424
CMN
1429 if (!git_config_get_path(&template_buf, cfg, "init.templatedir"))
1430 tdir = template_buf.ptr;
ca1b6e54 1431 giterr_clear();
0cd1c3bb
L
1432 }
1433
1434 if (!tdir) {
83634d38 1435 if (!(error = git_sysdir_find_template_dir(&template_buf)))
417472e3 1436 tdir = template_buf.ptr;
0cd1c3bb 1437 default_template = true;
662880ca 1438 }
ca1b6e54 1439
bafaf790 1440 if (tdir) {
62602547
ET
1441 uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS |
1442 GIT_CPDIR_SIMPLE_TO_MODE |
1443 GIT_CPDIR_COPY_DOTFILES;
517341c5
EL
1444 if (opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK)
1445 cpflags |= GIT_CPDIR_CHMOD_DIRS;
1446 error = git_futils_cp_r(tdir, repo_dir, cpflags, dmode);
bafaf790 1447 }
ca1b6e54 1448
0cd1c3bb
L
1449 git_buf_free(&template_buf);
1450 git_config_free(cfg);
1ca3e49f 1451
ca1b6e54 1452 if (error < 0) {
0cd1c3bb 1453 if (!default_template)
ca1b6e54
RB
1454 return error;
1455
1456 /* if template was default, ignore error and use internal */
1457 giterr_clear();
1458 external_tpl = false;
b7b1acfd 1459 error = 0;
ca1b6e54
RB
1460 }
1461 }
1462
1463 /* Copy internal template
1464 * - always ensure existence of dirs
1465 * - only create files if no external template was specified
1466 */
1467 for (tpl = repo_template; !error && tpl->path; ++tpl) {
bafaf790 1468 if (!tpl->content) {
517341c5
EL
1469 uint32_t mkdir_flags = GIT_MKDIR_PATH;
1470 if (chmod)
1471 mkdir_flags |= GIT_MKDIR_CHMOD;
1472
ac2fba0e
ET
1473 error = git_futils_mkdir_relative(
1474 tpl->path, repo_dir, dmode, mkdir_flags, NULL);
bafaf790 1475 }
ca1b6e54 1476 else if (!external_tpl) {
662880ca
RB
1477 const char *content = tpl->content;
1478
1479 if (opts->description && strcmp(tpl->path, GIT_DESC_FILE) == 0)
1480 content = opts->description;
1481
ca1b6e54
RB
1482 error = repo_write_template(
1483 repo_dir, false, tpl->path, tpl->mode, false, content);
662880ca 1484 }
dc34da6e
RB
1485 }
1486
ca1b6e54 1487 return error;
4b8e27c8 1488}
1489
3c42e4ef
RB
1490static int mkdir_parent(git_buf *buf, uint32_t mode, bool skip2)
1491{
0d1b094b
RB
1492 /* When making parent directories during repository initialization
1493 * don't try to set gid or grant world write access
1494 */
3c42e4ef 1495 return git_futils_mkdir(
ac2fba0e 1496 buf->ptr, mode & ~(S_ISGID | 0002),
3c42e4ef
RB
1497 GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR |
1498 (skip2 ? GIT_MKDIR_SKIP_LAST2 : GIT_MKDIR_SKIP_LAST));
1499}
1500
662880ca
RB
1501static int repo_init_directories(
1502 git_buf *repo_path,
1503 git_buf *wd_path,
1504 const char *given_repo,
1505 git_repository_init_options *opts)
4b8e27c8 1506{
662880ca 1507 int error = 0;
3c42e4ef 1508 bool is_bare, add_dotgit, has_dotgit, natural_wd;
ca1b6e54 1509 mode_t dirmode;
932d1baf 1510
3c42e4ef
RB
1511 /* There are three possible rules for what we are allowed to create:
1512 * - MKPATH means anything we need
1513 * - MKDIR means just the .git directory and its parent and the workdir
1514 * - Neither means only the .git directory can be created
1515 *
1516 * There are 5 "segments" of path that we might need to deal with:
1517 * 1. The .git directory
1518 * 2. The parent of the .git directory
1519 * 3. Everything above the parent of the .git directory
1520 * 4. The working directory (often the same as #2)
1521 * 5. Everything above the working directory (often the same as #3)
1522 *
1523 * For all directories created, we start with the init_mode value for
1524 * permissions and then strip off bits in some cases:
1525 *
1526 * For MKPATH, we create #3 (and #5) paths without S_ISGID or S_IWOTH
1527 * For MKPATH and MKDIR, we create #2 (and #4) without S_ISGID
1528 * For all rules, we create #1 using the untouched init_mode
1529 */
1530
662880ca 1531 /* set up repo path */
4b8e27c8 1532
3c42e4ef
RB
1533 is_bare = ((opts->flags & GIT_REPOSITORY_INIT_BARE) != 0);
1534
662880ca
RB
1535 add_dotgit =
1536 (opts->flags & GIT_REPOSITORY_INIT_NO_DOTGIT_DIR) == 0 &&
3c42e4ef 1537 !is_bare &&
662880ca
RB
1538 git__suffixcmp(given_repo, "/" DOT_GIT) != 0 &&
1539 git__suffixcmp(given_repo, "/" GIT_DIR) != 0;
4b8e27c8 1540
662880ca
RB
1541 if (git_buf_joinpath(repo_path, given_repo, add_dotgit ? GIT_DIR : "") < 0)
1542 return -1;
693b23c0 1543
662880ca
RB
1544 has_dotgit = (git__suffixcmp(repo_path->ptr, "/" GIT_DIR) == 0);
1545 if (has_dotgit)
1546 opts->flags |= GIT_REPOSITORY_INIT__HAS_DOTGIT;
1547
1548 /* set up workdir path */
1549
3c42e4ef 1550 if (!is_bare) {
662880ca 1551 if (opts->workdir_path) {
ca1b6e54
RB
1552 if (git_path_join_unrooted(
1553 wd_path, opts->workdir_path, repo_path->ptr, NULL) < 0)
1554 return -1;
662880ca
RB
1555 } else if (has_dotgit) {
1556 if (git_path_dirname_r(wd_path, repo_path->ptr) < 0)
1557 return -1;
1558 } else {
1559 giterr_set(GITERR_REPOSITORY, "Cannot pick working directory"
1560 " for non-bare repository that isn't a '.git' directory");
1561 return -1;
1562 }
693b23c0 1563
662880ca
RB
1564 if (git_path_to_dir(wd_path) < 0)
1565 return -1;
1566 } else {
1567 git_buf_clear(wd_path);
1568 }
1569
1570 natural_wd =
1571 has_dotgit &&
1572 wd_path->size > 0 &&
1573 wd_path->size + strlen(GIT_DIR) == repo_path->size &&
1574 memcmp(repo_path->ptr, wd_path->ptr, wd_path->size) == 0;
1575 if (natural_wd)
1576 opts->flags |= GIT_REPOSITORY_INIT__NATURAL_WD;
1577
662880ca
RB
1578 /* create directories as needed / requested */
1579
ca1b6e54 1580 dirmode = pick_dir_mode(opts);
662880ca 1581
3c42e4ef
RB
1582 if ((opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) {
1583 /* create path #5 */
1584 if (wd_path->size > 0 &&
1585 (error = mkdir_parent(wd_path, dirmode, false)) < 0)
1586 return error;
1587
1588 /* create path #3 (if not the same as #5) */
1589 if (!natural_wd &&
1590 (error = mkdir_parent(repo_path, dirmode, has_dotgit)) < 0)
1591 return error;
1592 }
1593
1594 if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 ||
1595 (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0)
1596 {
1597 /* create path #4 */
1598 if (wd_path->size > 0 &&
1599 (error = git_futils_mkdir(
ac2fba0e 1600 wd_path->ptr, dirmode & ~S_ISGID,
3c42e4ef
RB
1601 GIT_MKDIR_VERIFY_DIR)) < 0)
1602 return error;
1603
1604 /* create path #2 (if not the same as #4) */
1605 if (!natural_wd &&
1606 (error = git_futils_mkdir(
ac2fba0e 1607 repo_path->ptr, dirmode & ~S_ISGID,
3c42e4ef
RB
1608 GIT_MKDIR_VERIFY_DIR | GIT_MKDIR_SKIP_LAST)) < 0)
1609 return error;
662880ca 1610 }
662880ca 1611
ca1b6e54
RB
1612 if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 ||
1613 (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0 ||
1614 has_dotgit)
1615 {
3c42e4ef 1616 /* create path #1 */
ac2fba0e 1617 error = git_futils_mkdir(repo_path->ptr, dirmode,
18f08264 1618 GIT_MKDIR_VERIFY_DIR | ((dirmode & S_ISGID) ? GIT_MKDIR_CHMOD : 0));
662880ca 1619 }
ca1b6e54 1620
662880ca
RB
1621 /* prettify both directories now that they are created */
1622
1623 if (!error) {
1624 error = git_path_prettify_dir(repo_path, repo_path->ptr, NULL);
1625
1626 if (!error && wd_path->size > 0)
1627 error = git_path_prettify_dir(wd_path, wd_path->ptr, NULL);
1628 }
1629
1630 return error;
1631}
1632
1633static int repo_init_create_origin(git_repository *repo, const char *url)
1634{
1635 int error;
1636 git_remote *remote;
1637
29f27599 1638 if (!(error = git_remote_create(&remote, repo, GIT_REMOTE_ORIGIN, url))) {
662880ca
RB
1639 git_remote_free(remote);
1640 }
1641
1642 return error;
1643}
1644
1645int git_repository_init(
1646 git_repository **repo_out, const char *path, unsigned is_bare)
1647{
b4d13652 1648 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
662880ca 1649
662880ca
RB
1650 opts.flags = GIT_REPOSITORY_INIT_MKPATH; /* don't love this default */
1651 if (is_bare)
1652 opts.flags |= GIT_REPOSITORY_INIT_BARE;
1653
1654 return git_repository_init_ext(repo_out, path, &opts);
1655}
1656
1657int git_repository_init_ext(
c9fc4a6f 1658 git_repository **out,
662880ca
RB
1659 const char *given_repo,
1660 git_repository_init_options *opts)
1661{
1662 int error;
1663 git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT;
466d2e7a 1664 const char *wd;
662880ca 1665
c9fc4a6f 1666 assert(out && given_repo && opts);
662880ca 1667
c7231c45 1668 GITERR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options");
b4d13652 1669
662880ca
RB
1670 error = repo_init_directories(&repo_path, &wd_path, given_repo, opts);
1671 if (error < 0)
693b23c0 1672 goto cleanup;
662880ca 1673
466d2e7a 1674 wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_buf_cstr(&wd_path);
662880ca
RB
1675 if (valid_repository_path(&repo_path)) {
1676
1677 if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) {
1678 giterr_set(GITERR_REPOSITORY,
1679 "Attempt to reinitialize '%s'", given_repo);
1680 error = GIT_EEXISTS;
1681 goto cleanup;
1682 }
1683
1684 opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT;
1685
ca1b6e54 1686 error = repo_init_config(
466d2e7a 1687 repo_path.ptr, wd, opts->flags, opts->mode);
662880ca
RB
1688
1689 /* TODO: reinitialize the templates */
1690 }
1691 else {
1692 if (!(error = repo_init_structure(
466d2e7a 1693 repo_path.ptr, wd, opts)) &&
ca1b6e54 1694 !(error = repo_init_config(
466d2e7a 1695 repo_path.ptr, wd, opts->flags, opts->mode)))
662880ca 1696 error = repo_init_create_head(
5173ea92 1697 repo_path.ptr, opts->initial_head);
cb8a7961 1698 }
662880ca
RB
1699 if (error < 0)
1700 goto cleanup;
1701
5173ea92 1702 error = git_repository_open(out, repo_path.ptr);
d2d6912e 1703
662880ca 1704 if (!error && opts->origin_url)
c9fc4a6f 1705 error = repo_init_create_origin(*out, opts->origin_url);
693b23c0 1706
1707cleanup:
662880ca
RB
1708 git_buf_free(&repo_path);
1709 git_buf_free(&wd_path);
1710
1711 return error;
40c44d2f 1712}
35502d2e 1713
c682886e 1714int git_repository_head_detached(git_repository *repo)
35502d2e
CMN
1715{
1716 git_reference *ref;
9462c471 1717 git_odb *odb = NULL;
cb8a7961 1718 int exists;
9462c471 1719
cb8a7961
VM
1720 if (git_repository_odb__weakptr(&odb, repo) < 0)
1721 return -1;
35502d2e 1722
cb8a7961
VM
1723 if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0)
1724 return -1;
35502d2e 1725
75abd2b9
MS
1726 if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1727 git_reference_free(ref);
35502d2e 1728 return 0;
75abd2b9 1729 }
35502d2e 1730
2508cc66 1731 exists = git_odb_exists(odb, git_reference_target(ref));
75abd2b9
MS
1732
1733 git_reference_free(ref);
cb8a7961 1734 return exists;
35502d2e
CMN
1735}
1736
3601c4bf 1737int git_repository_head(git_reference **head_out, git_repository *repo)
35502d2e 1738{
b1a3a70e 1739 git_reference *head;
8b05bea8 1740 int error;
1741
b1a3a70e 1742 if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
1743 return error;
1744
1745 if (git_reference_type(head) == GIT_REF_OID) {
1746 *head_out = head;
1747 return 0;
1748 }
1749
2508cc66 1750 error = git_reference_lookup_resolved(head_out, repo, git_reference_symbolic_target(head), -1);
b1a3a70e 1751 git_reference_free(head);
8b05bea8 1752
605da51a 1753 return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error;
3601c4bf 1754}
1755
605da51a 1756int git_repository_head_unborn(git_repository *repo)
3601c4bf 1757{
cb8a7961 1758 git_reference *ref = NULL;
3601c4bf 1759 int error;
1760
1761 error = git_repository_head(&ref, repo);
cb8a7961 1762 git_reference_free(ref);
35502d2e 1763
7c9bf891
ET
1764 if (error == GIT_EUNBORNBRANCH) {
1765 giterr_clear();
cb8a7961 1766 return 1;
7c9bf891 1767 }
75abd2b9 1768
cb8a7961
VM
1769 if (error < 0)
1770 return -1;
1771
1772 return 0;
35502d2e 1773}
e0011be3 1774
0066955d 1775static int at_least_one_cb(const char *refname, void *payload)
41233c40 1776{
6091457e 1777 GIT_UNUSED(refname);
1778 GIT_UNUSED(payload);
25e0b157 1779 return GIT_PASSTHROUGH;
6091457e 1780}
41233c40 1781
6091457e 1782static int repo_contains_no_reference(git_repository *repo)
1783{
ec24e542 1784 int error = git_reference_foreach_name(repo, &at_least_one_cb, NULL);
0f489fb2 1785
25e0b157 1786 if (error == GIT_PASSTHROUGH)
0f489fb2 1787 return 0;
ec24e542 1788
e976b56d
RB
1789 if (!error)
1790 return 1;
ec24e542 1791
e976b56d 1792 return error;
6091457e 1793}
75abd2b9 1794
6091457e 1795int git_repository_is_empty(git_repository *repo)
1796{
1797 git_reference *head = NULL;
42181836 1798 int is_empty = 0;
cb8a7961 1799
6091457e 1800 if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0)
cb8a7961
VM
1801 return -1;
1802
42181836
RB
1803 if (git_reference_type(head) == GIT_REF_SYMBOLIC)
1804 is_empty =
1805 (strcmp(git_reference_symbolic_target(head),
1806 GIT_REFS_HEADS_DIR "master") == 0) &&
1807 repo_contains_no_reference(repo);
6091457e 1808
6091457e 1809 git_reference_free(head);
42181836
RB
1810
1811 return is_empty;
41233c40
VM
1812}
1813
9462c471 1814const char *git_repository_path(git_repository *repo)
4a34b3a9 1815{
1816 assert(repo);
9462c471
VM
1817 return repo->path_repository;
1818}
4a34b3a9 1819
9462c471
VM
1820const char *git_repository_workdir(git_repository *repo)
1821{
1822 assert(repo);
602ee38b 1823
9462c471
VM
1824 if (repo->is_bare)
1825 return NULL;
602ee38b 1826
9462c471
VM
1827 return repo->workdir;
1828}
602ee38b 1829
991a56c7
RB
1830int git_repository_set_workdir(
1831 git_repository *repo, const char *workdir, int update_gitlink)
9462c471 1832{
991a56c7 1833 int error = 0;
b78fb64d 1834 git_buf path = GIT_BUF_INIT;
1835
9462c471 1836 assert(repo && workdir);
602ee38b 1837
b78fb64d 1838 if (git_path_prettify_dir(&path, workdir, NULL) < 0)
1839 return -1;
9462c471 1840
991a56c7
RB
1841 if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0)
1842 return 0;
9462c471 1843
991a56c7
RB
1844 if (update_gitlink) {
1845 git_config *config;
1846
1847 if (git_repository_config__weakptr(&config, repo) < 0)
1848 return -1;
1849
bc737620 1850 error = repo_write_gitlink(path.ptr, git_repository_path(repo), false);
991a56c7
RB
1851
1852 /* passthrough error means gitlink is unnecessary */
1853 if (error == GIT_PASSTHROUGH)
54b2a37a 1854 error = git_config_delete_entry(config, "core.worktree");
991a56c7
RB
1855 else if (!error)
1856 error = git_config_set_string(config, "core.worktree", path.ptr);
1857
1858 if (!error)
1859 error = git_config_set_bool(config, "core.bare", false);
1860 }
1861
1862 if (!error) {
1863 char *old_workdir = repo->workdir;
1864
1865 repo->workdir = git_buf_detach(&path);
1866 repo->is_bare = 0;
1867
1868 git__free(old_workdir);
1869 }
1870
1871 return error;
4a34b3a9 1872}
fa9bcd81 1873
1874int git_repository_is_bare(git_repository *repo)
1875{
1876 assert(repo);
1877 return repo->is_bare;
1878}
f917481e 1879
1fbeb2f0
RB
1880int git_repository_set_bare(git_repository *repo)
1881{
1882 int error;
1883 git_config *config;
1884
1885 assert(repo);
1886
1887 if (repo->is_bare)
1888 return 0;
1889
74240afb
T
1890 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
1891 return error;
1892
b2a7bcdb 1893 if ((error = git_config_set_bool(config, "core.bare", true)) < 0)
74240afb 1894 return error;
1fbeb2f0 1895
74240afb
T
1896 if ((error = git_config__update_entry(config, "core.worktree", NULL, true, true)) < 0)
1897 return error;
1fbeb2f0
RB
1898
1899 git__free(repo->workdir);
1900 repo->workdir = NULL;
1fbeb2f0
RB
1901 repo->is_bare = 1;
1902
74240afb 1903 return 0;
1fbeb2f0
RB
1904}
1905
f917481e
RB
1906int git_repository_head_tree(git_tree **tree, git_repository *repo)
1907{
5cec896a 1908 git_reference *head;
1909 git_object *obj;
1910 int error;
f917481e 1911
5cec896a 1912 if ((error = git_repository_head(&head, repo)) < 0)
1913 return error;
f917481e 1914
5cec896a 1915 if ((error = git_reference_peel(&obj, head, GIT_OBJ_TREE)) < 0)
1916 goto cleanup;
f917481e
RB
1917
1918 *tree = (git_tree *)obj;
5cec896a 1919
1920cleanup:
1921 git_reference_free(head);
1922 return error;
f917481e 1923}
074841ec 1924
867a36f3
ET
1925int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head)
1926{
1927 git_filebuf file = GIT_FILEBUF_INIT;
1928 git_buf file_path = GIT_BUF_INIT;
1929 char orig_head_str[GIT_OID_HEXSZ];
1930 int error = 0;
1931
1932 git_oid_fmt(orig_head_str, orig_head);
1933
1934 if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 &&
1935 (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 &&
1936 (error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0)
1937 error = git_filebuf_commit(&file);
1938
1939 if (error < 0)
1940 git_filebuf_cleanup(&file);
1941
1942 git_buf_free(&file_path);
1943
1944 return error;
1945}
1946
3158e2fe 1947int git_repository_message(git_buf *out, git_repository *repo)
074841ec 1948{
7a3bd1e7 1949 git_buf path = GIT_BUF_INIT;
0ac349a9 1950 struct stat st;
0ac349a9 1951 int error;
074841ec 1952
7a3bd1e7 1953 git_buf_sanitize(out);
3d1c9f61 1954
632d8b23 1955 if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
0ac349a9 1956 return -1;
074841ec 1957
e9ca852e 1958 if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) {
074841ec
CMN
1959 if (errno == ENOENT)
1960 error = GIT_ENOTFOUND;
1a9e406c 1961 giterr_set(GITERR_OS, "Could not access message file");
3158e2fe
RB
1962 } else {
1963 error = git_futils_readbuffer(out, git_buf_cstr(&path));
0ac349a9 1964 }
074841ec 1965
7a3bd1e7 1966 git_buf_free(&path);
e9ca852e
RB
1967
1968 return error;
074841ec
CMN
1969}
1970
1971int git_repository_message_remove(git_repository *repo)
1972{
0ac349a9
VM
1973 git_buf path = GIT_BUF_INIT;
1974 int error;
074841ec 1975
632d8b23 1976 if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
0ac349a9 1977 return -1;
074841ec
CMN
1978
1979 error = p_unlink(git_buf_cstr(&path));
1980 git_buf_free(&path);
1981
1982 return error;
1983}
47bfa0be
RB
1984
1985int git_repository_hashfile(
0cb16fe9
L
1986 git_oid *out,
1987 git_repository *repo,
1988 const char *path,
1989 git_otype type,
1990 const char *as_path)
47bfa0be
RB
1991{
1992 int error;
85d54812 1993 git_filter_list *fl = NULL;
b1127a30 1994 git_file fd = -1;
47bfa0be
RB
1995 git_off_t len;
1996 git_buf full_path = GIT_BUF_INIT;
1997
a13fb55a
RB
1998 assert(out && path && repo); /* as_path can be NULL */
1999
2000 /* At some point, it would be nice if repo could be NULL to just
2001 * apply filter rules defined in system and global files, but for
2002 * now that is not possible because git_filters_load() needs it.
2003 */
47bfa0be
RB
2004
2005 error = git_path_join_unrooted(
526182d2 2006 &full_path, path, git_repository_workdir(repo), NULL);
47bfa0be
RB
2007 if (error < 0)
2008 return error;
2009
2010 if (!as_path)
2011 as_path = path;
2012
2013 /* passing empty string for "as_path" indicated --no-filters */
2014 if (strlen(as_path) > 0) {
4b11f25a 2015 error = git_filter_list_load(
5269008c 2016 &fl, repo, NULL, as_path,
795eaccd 2017 GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT);
47bfa0be
RB
2018 if (error < 0)
2019 return error;
2020 } else {
2021 error = 0;
2022 }
2023
2024 /* at this point, error is a count of the number of loaded filters */
2025
2026 fd = git_futils_open_ro(full_path.ptr);
2027 if (fd < 0) {
2028 error = fd;
2029 goto cleanup;
2030 }
2031
2032 len = git_futils_filesize(fd);
2033 if (len < 0) {
75050223 2034 error = (int)len;
47bfa0be
RB
2035 goto cleanup;
2036 }
2037
2038 if (!git__is_sizet(len)) {
2039 giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
2040 error = -1;
2041 goto cleanup;
2042 }
2043
85d54812 2044 error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, fl);
47bfa0be
RB
2045
2046cleanup:
b1127a30
SS
2047 if (fd >= 0)
2048 p_close(fd);
85d54812 2049 git_filter_list_free(fl);
47bfa0be
RB
2050 git_buf_free(&full_path);
2051
2052 return error;
2053}
2054
4e498646 2055static int checkout_message(git_buf *out, git_reference *old, const char *new)
44af67a8 2056{
4e498646
CMN
2057 git_buf_puts(out, "checkout: moving from ");
2058
2059 if (git_reference_type(old) == GIT_REF_SYMBOLIC)
2060 git_buf_puts(out, git_reference__shorthand(git_reference_symbolic_target(old)));
2061 else
2062 git_buf_puts(out, git_oid_tostr_s(git_reference_target(old)));
2063
2064 git_buf_puts(out, " to ");
2065
2066 if (git_reference__is_branch(new))
2067 git_buf_puts(out, git_reference__shorthand(new));
2068 else
2069 git_buf_puts(out, new);
2070
2071 if (git_buf_oom(out))
2072 return -1;
2073
2074 return 0;
44af67a8 2075}
2076
2077int git_repository_set_head(
2078 git_repository* repo,
4e498646 2079 const char* refname)
44af67a8 2080{
4e498646
CMN
2081 git_reference *ref = NULL, *current = NULL, *new_head = NULL;
2082 git_buf log_message = GIT_BUF_INIT;
44af67a8 2083 int error;
2084
2085 assert(repo && refname);
2086
4e498646
CMN
2087 if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
2088 return error;
2089
2090 if ((error = checkout_message(&log_message, current, refname)) < 0)
2091 goto cleanup;
2092
44af67a8 2093 error = git_reference_lookup(&ref, repo, refname);
2094 if (error < 0 && error != GIT_ENOTFOUND)
4e498646 2095 goto cleanup;
44af67a8 2096
2097 if (!error) {
94f263f5
BS
2098 if (git_reference_is_branch(ref)) {
2099 error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE,
4e498646 2100 git_reference_name(ref), true, git_buf_cstr(&log_message));
94f263f5 2101 } else {
4e498646 2102 error = git_repository_set_head_detached(repo, git_reference_target(ref));
94f263f5 2103 }
4e498646 2104 } else if (git_reference__is_branch(refname)) {
94f263f5 2105 error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname,
4e498646 2106 true, git_buf_cstr(&log_message));
94f263f5 2107 }
44af67a8 2108
4e498646 2109cleanup:
fe21d708 2110 git_buf_free(&log_message);
4e498646 2111 git_reference_free(current);
44af67a8 2112 git_reference_free(ref);
2113 git_reference_free(new_head);
2114 return error;
2115}
2116
62d38a1d 2117static int detach(git_repository *repo, const git_oid *id, const char *from)
4ebe38bd 2118{
2119 int error;
4e498646
CMN
2120 git_buf log_message = GIT_BUF_INIT;
2121 git_object *object = NULL, *peeled = NULL;
2122 git_reference *new_head = NULL, *current = NULL;
4ebe38bd 2123
62d38a1d 2124 assert(repo && id);
4ebe38bd 2125
4e498646 2126 if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
4ebe38bd 2127 return error;
2128
62d38a1d 2129 if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0)
4e498646
CMN
2130 goto cleanup;
2131
4ebe38bd 2132 if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0)
2133 goto cleanup;
2134
62d38a1d
CMN
2135 if (from == NULL)
2136 from = git_oid_tostr_s(git_object_id(peeled));
2137
2138 if ((error = checkout_message(&log_message, current, from)) < 0)
4e498646
CMN
2139 goto cleanup;
2140
2141 error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message));
4ebe38bd 2142
2143cleanup:
fe21d708 2144 git_buf_free(&log_message);
4ebe38bd 2145 git_object_free(object);
2146 git_object_free(peeled);
4e498646 2147 git_reference_free(current);
4ebe38bd 2148 git_reference_free(new_head);
2149 return error;
2150}
2151
62d38a1d
CMN
2152int git_repository_set_head_detached(
2153 git_repository* repo,
2154 const git_oid* commitish)
2155{
2156 return detach(repo, commitish, NULL);
2157}
2158
2159int git_repository_set_head_detached_from_annotated(
2160 git_repository *repo,
2161 const git_annotated_commit *commitish)
2162{
2163 assert(repo && commitish);
2164
2165 return detach(repo, git_annotated_commit_id(commitish), commitish->ref_name);
2166}
2167
4e498646 2168int git_repository_detach_head(git_repository* repo)
3f4c3072 2169{
4e498646 2170 git_reference *old_head = NULL, *new_head = NULL, *current = NULL;
3f4c3072 2171 git_object *object = NULL;
4e498646 2172 git_buf log_message = GIT_BUF_INIT;
8b05bea8 2173 int error;
3f4c3072 2174
2175 assert(repo);
2176
4e498646 2177 if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
8b05bea8 2178 return error;
3f4c3072 2179
4e498646
CMN
2180 if ((error = git_repository_head(&old_head, repo)) < 0)
2181 goto cleanup;
2182
2508cc66 2183 if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJ_COMMIT)) < 0)
3f4c3072 2184 goto cleanup;
2185
4e498646
CMN
2186 if ((error = checkout_message(&log_message, current, git_oid_tostr_s(git_object_id(object)))) < 0)
2187 goto cleanup;
2188
010cec3a 2189 error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head),
4e498646 2190 1, git_buf_cstr(&log_message));
3f4c3072 2191
2192cleanup:
fe21d708 2193 git_buf_free(&log_message);
3f4c3072 2194 git_object_free(object);
2195 git_reference_free(old_head);
2196 git_reference_free(new_head);
4e498646 2197 git_reference_free(current);
3f4c3072 2198 return error;
2199}
632d8b23 2200
31966d20 2201/**
2202 * Loosely ported from git.git
2203 * https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh#L198-289
2204 */
632d8b23
ET
2205int git_repository_state(git_repository *repo)
2206{
2207 git_buf repo_path = GIT_BUF_INIT;
2208 int state = GIT_REPOSITORY_STATE_NONE;
2209
2210 assert(repo);
2211
2212 if (git_buf_puts(&repo_path, repo->path_repository) < 0)
2213 return -1;
2214
31966d20 2215 if (git_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE))
2216 state = GIT_REPOSITORY_STATE_REBASE_INTERACTIVE;
2217 else if (git_path_contains_dir(&repo_path, GIT_REBASE_MERGE_DIR))
2218 state = GIT_REPOSITORY_STATE_REBASE_MERGE;
2219 else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_REBASING_FILE))
2220 state = GIT_REPOSITORY_STATE_REBASE;
2221 else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_APPLYING_FILE))
2222 state = GIT_REPOSITORY_STATE_APPLY_MAILBOX;
2223 else if (git_path_contains_dir(&repo_path, GIT_REBASE_APPLY_DIR))
2224 state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE;
2225 else if (git_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE))
632d8b23 2226 state = GIT_REPOSITORY_STATE_MERGE;
2ea40fda 2227 else if (git_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE)) {
632d8b23 2228 state = GIT_REPOSITORY_STATE_REVERT;
2ea40fda
CMN
2229 if (git_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) {
2230 state = GIT_REPOSITORY_STATE_REVERT_SEQUENCE;
2231 }
2232 } else if (git_path_contains_file(&repo_path, GIT_CHERRYPICK_HEAD_FILE)) {
0ba4dca5 2233 state = GIT_REPOSITORY_STATE_CHERRYPICK;
2ea40fda
CMN
2234 if (git_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) {
2235 state = GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE;
2236 }
2237 } else if (git_path_contains_file(&repo_path, GIT_BISECT_LOG_FILE))
31966d20 2238 state = GIT_REPOSITORY_STATE_BISECT;
632d8b23
ET
2239
2240 git_buf_free(&repo_path);
2241 return state;
2242}
93d8f77f 2243
c3dcbe84
VM
2244int git_repository__cleanup_files(
2245 git_repository *repo, const char *files[], size_t files_len)
bab0b9f2 2246{
c3dcbe84 2247 git_buf buf = GIT_BUF_INIT;
bab0b9f2 2248 size_t i;
c3dcbe84 2249 int error;
bab0b9f2 2250
c3dcbe84
VM
2251 for (error = 0, i = 0; !error && i < files_len; ++i) {
2252 const char *path;
bab0b9f2 2253
c3dcbe84
VM
2254 if (git_buf_joinpath(&buf, repo->path_repository, files[i]) < 0)
2255 return -1;
bab0b9f2 2256
c3dcbe84
VM
2257 path = git_buf_cstr(&buf);
2258
2259 if (git_path_isfile(path)) {
2260 error = p_unlink(path);
2261 } else if (git_path_isdir(path)) {
2262 error = git_futils_rmdir_r(path, NULL,
2263 GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS);
2264 }
2265
2266 git_buf_clear(&buf);
2267 }
bab0b9f2 2268
c3dcbe84 2269 git_buf_free(&buf);
bab0b9f2
ET
2270 return error;
2271}
2272
2273static const char *state_files[] = {
2274 GIT_MERGE_HEAD_FILE,
2275 GIT_MERGE_MODE_FILE,
2276 GIT_MERGE_MSG_FILE,
2277 GIT_REVERT_HEAD_FILE,
0ba4dca5 2278 GIT_CHERRYPICK_HEAD_FILE,
c0311295
JG
2279 GIT_BISECT_LOG_FILE,
2280 GIT_REBASE_MERGE_DIR,
2281 GIT_REBASE_APPLY_DIR,
2ea40fda 2282 GIT_SEQUENCER_DIR,
bab0b9f2
ET
2283};
2284
2285int git_repository_state_cleanup(git_repository *repo)
2286{
2287 assert(repo);
2288
2289 return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
2290}
2291
93d8f77f
BS
2292int git_repository_is_shallow(git_repository *repo)
2293{
2294 git_buf path = GIT_BUF_INIT;
2295 struct stat st;
6f0b8142 2296 int error;
93d8f77f 2297
3dbd9a0e
JG
2298 if ((error = git_buf_joinpath(&path, repo->path_repository, "shallow")) < 0)
2299 return error;
2300
6f0b8142
BS
2301 error = git_path_lstat(path.ptr, &st);
2302 git_buf_free(&path);
93d8f77f 2303
9bda5fb8
BS
2304 if (error == GIT_ENOTFOUND) {
2305 giterr_clear();
93d8f77f 2306 return 0;
9bda5fb8
BS
2307 }
2308
864535cf
BS
2309 if (error < 0)
2310 return error;
2311 return st.st_size == 0 ? 0 : 1;
93d8f77f 2312}
b9f81997 2313
702efc89
RB
2314int git_repository_init_init_options(
2315 git_repository_init_options *opts, unsigned int version)
b9f81997 2316{
702efc89
RB
2317 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2318 opts, version, git_repository_init_options,
2319 GIT_REPOSITORY_INIT_OPTIONS_INIT);
2320 return 0;
b9f81997 2321}
659cf202
CMN
2322
2323int git_repository_ident(const char **name, const char **email, const git_repository *repo)
2324{
2325 *name = repo->ident_name;
2326 *email = repo->ident_email;
2327
2328 return 0;
2329}
2330
2331int git_repository_set_ident(git_repository *repo, const char *name, const char *email)
2332{
2333 char *tmp_name = NULL, *tmp_email = NULL;
2334
2335 if (name) {
2336 tmp_name = git__strdup(name);
2337 GITERR_CHECK_ALLOC(tmp_name);
2338 }
2339
2340 if (email) {
2341 tmp_email = git__strdup(email);
2342 GITERR_CHECK_ALLOC(tmp_email);
2343 }
2344
2345 tmp_name = git__swap(repo->ident_name, tmp_name);
2346 tmp_email = git__swap(repo->ident_email, tmp_email);
2347
2348 git__free(tmp_name);
2349 git__free(tmp_email);
2350
2351 return 0;
2352}