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