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