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