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