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