]> git.proxmox.com Git - libgit2.git/blame - src/repository.c
Introduce git_revert to revert a single commit
[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 ||
1d3a8aeb 819 git_filebuf_open(&ref, ref_path.ptr, 0, GIT_REFS_FILE_MODE) < 0)
662880ca
RB
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 ||
1d3a8aeb 831 git_filebuf_commit(&ref) < 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;
fac66990 846
847 if (p_stat(file_path, &st1) < 0)
848 return false;
849
850 if (p_chmod(file_path, st1.st_mode ^ S_IXUSR) < 0)
851 return false;
852
853 if (p_stat(file_path, &st2) < 0)
854 return false;
855
6b7991e2 856 return (st1.st_mode != st2.st_mode);
fac66990 857}
858
693b23c0 859static bool is_filesystem_case_insensitive(const char *gitdir_path)
860{
861 git_buf path = GIT_BUF_INIT;
6b7991e2 862 int is_insensitive = -1;
693b23c0 863
6b7991e2
RB
864 if (!git_buf_joinpath(&path, gitdir_path, "CoNfIg"))
865 is_insensitive = git_path_exists(git_buf_cstr(&path));
693b23c0 866
693b23c0 867 git_buf_free(&path);
6b7991e2 868 return is_insensitive;
693b23c0 869}
870
ca1b6e54
RB
871static bool are_symlinks_supported(const char *wd_path)
872{
873 git_buf path = GIT_BUF_INIT;
874 int fd;
875 struct stat st;
6b7991e2 876 int symlinks_supported = -1;
ca1b6e54 877
1d3a8aeb 878 if ((fd = git_futils_mktmp(&path, wd_path, 0666)) < 0 ||
ca1b6e54
RB
879 p_close(fd) < 0 ||
880 p_unlink(path.ptr) < 0 ||
881 p_symlink("testing", path.ptr) < 0 ||
882 p_lstat(path.ptr, &st) < 0)
6b7991e2 883 symlinks_supported = false;
ca1b6e54 884 else
6b7991e2 885 symlinks_supported = (S_ISLNK(st.st_mode) != 0);
ca1b6e54
RB
886
887 (void)p_unlink(path.ptr);
888 git_buf_free(&path);
889
6b7991e2
RB
890 return symlinks_supported;
891}
892
af302aca
RB
893#ifdef GIT_USE_ICONV
894
6b7991e2
RB
895static const char *nfc_file = "\xC3\x85\x73\x74\x72\xC3\xB6\x6D.XXXXXX";
896static const char *nfd_file = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D.XXXXXX";
897
840fb4fc
RB
898/* Check if the platform is decomposing unicode data for us. We will
899 * emulate core Git and prefer to use precomposed unicode data internally
900 * on these platforms, composing the decomposed unicode on the fly.
901 *
902 * This mainly happens on the Mac where HDFS stores filenames as
903 * decomposed unicode. Even on VFAT and SAMBA file systems, the Mac will
904 * return decomposed unicode from readdir() even when the actual
905 * filesystem is storing precomposed unicode.
6b7991e2 906 */
840fb4fc 907static bool does_fs_decompose_unicode_paths(const char *wd_path)
6b7991e2
RB
908{
909 git_buf path = GIT_BUF_INIT;
910 int fd;
840fb4fc 911 bool found_decomposed = false;
6b7991e2
RB
912 char tmp[6];
913
914 /* Create a file using a precomposed path and then try to find it
915 * using the decomposed name. If the lookup fails, then we will mark
916 * that we should precompose unicode for this repository.
917 */
918 if (git_buf_joinpath(&path, wd_path, nfc_file) < 0 ||
919 (fd = p_mkstemp(path.ptr)) < 0)
840fb4fc 920 goto done;
6b7991e2
RB
921 p_close(fd);
922
923 /* record trailing digits generated by mkstemp */
924 memcpy(tmp, path.ptr + path.size - sizeof(tmp), sizeof(tmp));
925
926 /* try to look up as NFD path */
927 if (git_buf_joinpath(&path, wd_path, nfd_file) < 0)
840fb4fc 928 goto done;
6b7991e2
RB
929 memcpy(path.ptr + path.size - sizeof(tmp), tmp, sizeof(tmp));
930
840fb4fc 931 found_decomposed = git_path_exists(path.ptr);
6b7991e2 932
840fb4fc 933 /* remove temporary file (using original precomposed path) */
6b7991e2 934 if (git_buf_joinpath(&path, wd_path, nfc_file) < 0)
840fb4fc 935 goto done;
6b7991e2
RB
936 memcpy(path.ptr + path.size - sizeof(tmp), tmp, sizeof(tmp));
937
938 (void)p_unlink(path.ptr);
939
840fb4fc 940done:
6b7991e2 941 git_buf_free(&path);
840fb4fc 942 return found_decomposed;
ca1b6e54
RB
943}
944
af302aca
RB
945#endif
946
270160b9 947static int create_empty_file(const char *path, mode_t mode)
948{
949 int fd;
950
951 if ((fd = p_creat(path, mode)) < 0) {
952 giterr_set(GITERR_OS, "Error while creating '%s'", path);
953 return -1;
954 }
955
956 if (p_close(fd) < 0) {
957 giterr_set(GITERR_OS, "Error while closing '%s'", path);
958 return -1;
959 }
960
961 return 0;
962}
963
14997dc5
RB
964static int repo_local_config(
965 git_config **out,
966 git_buf *config_dir,
967 git_repository *repo,
968 const char *repo_dir)
9462c471 969{
ca1b6e54 970 int error = 0;
14997dc5
RB
971 git_config *parent;
972 const char *cfg_path;
9462c471 973
14997dc5 974 if (git_buf_joinpath(config_dir, repo_dir, GIT_CONFIG_FILENAME_INREPO) < 0)
cb8a7961 975 return -1;
14997dc5 976 cfg_path = git_buf_cstr(config_dir);
9462c471 977
14997dc5 978 /* make LOCAL config if missing */
5173ea92
RB
979 if (!git_path_isfile(cfg_path) &&
980 (error = create_empty_file(cfg_path, GIT_CONFIG_FILE_MODE)) < 0)
14997dc5 981 return error;
270160b9 982
14997dc5
RB
983 /* if no repo, just open that file directly */
984 if (!repo)
985 return git_config_open_ondisk(out, cfg_path);
986
987 /* otherwise, open parent config and get that level */
988 if ((error = git_repository_config__weakptr(&parent, repo)) < 0)
989 return error;
990
991 if (git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL) < 0) {
5173ea92
RB
992 giterr_clear();
993
994 if (!(error = git_config_add_file_ondisk(
995 parent, cfg_path, GIT_CONFIG_LEVEL_LOCAL, false)))
14997dc5 996 error = git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL);
cb8a7961 997 }
9462c471 998
14997dc5
RB
999 git_config_free(parent);
1000
1001 return error;
1002}
1003
1004static int repo_init_fs_configs(
1005 git_config *cfg,
1006 const char *cfg_path,
1007 const char *repo_dir,
1008 const char *work_dir,
1009 bool update_ignorecase)
1010{
1011 int error = 0;
1012
1013 if (!work_dir)
1014 work_dir = repo_dir;
1015
1016 if ((error = git_config_set_bool(
1017 cfg, "core.filemode", is_chmod_supported(cfg_path))) < 0)
1018 return error;
1019
1020 if (!are_symlinks_supported(work_dir)) {
1021 if ((error = git_config_set_bool(cfg, "core.symlinks", false)) < 0)
1022 return error;
1023 } else if (git_config_delete_entry(cfg, "core.symlinks") < 0)
1024 giterr_clear();
2c227b8b 1025
14997dc5
RB
1026 if (update_ignorecase) {
1027 if (is_filesystem_case_insensitive(repo_dir)) {
1028 if ((error = git_config_set_bool(cfg, "core.ignorecase", true)) < 0)
1029 return error;
1030 } else if (git_config_delete_entry(cfg, "core.ignorecase") < 0)
1031 giterr_clear();
1032 }
662880ca 1033
af302aca 1034#ifdef GIT_USE_ICONV
14997dc5
RB
1035 if ((error = git_config_set_bool(
1036 cfg, "core.precomposeunicode",
1037 does_fs_decompose_unicode_paths(work_dir))) < 0)
1038 return error;
6b7991e2
RB
1039#endif
1040
14997dc5
RB
1041 return 0;
1042}
7623b1b6 1043
14997dc5
RB
1044static int repo_init_config(
1045 const char *repo_dir,
1046 const char *work_dir,
1047 uint32_t flags,
1048 uint32_t mode)
1049{
1050 int error = 0;
1051 git_buf cfg_path = GIT_BUF_INIT;
1052 git_config *config = NULL;
1053 bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
1054 bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
1055
1056 if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0)
1057 goto cleanup;
1058
1059 if (is_reinit && (error = check_repositoryformatversion(config)) < 0)
1060 goto cleanup;
1061
1062#define SET_REPO_CONFIG(TYPE, NAME, VAL) do { \
1063 if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \
1064 goto cleanup; } while (0)
1065
1066 SET_REPO_CONFIG(bool, "core.bare", is_bare);
1067 SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION);
1068
1069 if ((error = repo_init_fs_configs(
1070 config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0)
1071 goto cleanup;
5173ea92 1072
6b7991e2
RB
1073 if (!is_bare) {
1074 SET_REPO_CONFIG(bool, "core.logallrefupdates", true);
ca1b6e54 1075
14997dc5 1076 if (!(flags & GIT_REPOSITORY_INIT__NATURAL_WD))
ca1b6e54 1077 SET_REPO_CONFIG(string, "core.worktree", work_dir);
14997dc5 1078 else if (is_reinit) {
54b2a37a 1079 if (git_config_delete_entry(config, "core.worktree") < 0)
89cd5708 1080 giterr_clear();
ca1b6e54 1081 }
ca1b6e54
RB
1082 }
1083
5173ea92 1084 if (mode == GIT_REPOSITORY_INIT_SHARED_GROUP) {
662880ca
RB
1085 SET_REPO_CONFIG(int32, "core.sharedrepository", 1);
1086 SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true);
ca1b6e54 1087 }
5173ea92 1088 else if (mode == GIT_REPOSITORY_INIT_SHARED_ALL) {
662880ca
RB
1089 SET_REPO_CONFIG(int32, "core.sharedrepository", 2);
1090 SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true);
1091 }
9462c471 1092
ca1b6e54 1093cleanup:
14997dc5 1094 git_buf_free(&cfg_path);
9462c471 1095 git_config_free(config);
662880ca 1096
ca1b6e54 1097 return error;
d2d6912e 1098}
e1f8cad0 1099
867f7c9b 1100static int repo_reinit_submodule_fs(git_submodule *sm, const char *n, void *p)
5173ea92 1101{
14997dc5
RB
1102 git_repository *smrepo = NULL;
1103 GIT_UNUSED(n); GIT_UNUSED(p);
5173ea92 1104
14997dc5 1105 if (git_submodule_open(&smrepo, sm) < 0 ||
867f7c9b 1106 git_repository_reinit_filesystem(smrepo, true) < 0)
14997dc5
RB
1107 giterr_clear();
1108 git_repository_free(smrepo);
5173ea92 1109
14997dc5
RB
1110 return 0;
1111}
5173ea92 1112
867f7c9b 1113int git_repository_reinit_filesystem(git_repository *repo, int recurse)
14997dc5
RB
1114{
1115 int error = 0;
1116 git_buf path = GIT_BUF_INIT;
1117 git_config *config = NULL;
1118 const char *repo_dir = git_repository_path(repo);
5173ea92 1119
14997dc5
RB
1120 if (!(error = repo_local_config(&config, &path, repo, repo_dir)))
1121 error = repo_init_fs_configs(
1122 config, path.ptr, repo_dir, git_repository_workdir(repo), true);
5173ea92 1123
14997dc5
RB
1124 git_config_free(config);
1125 git_buf_free(&path);
5173ea92 1126
5173ea92
RB
1127 git_repository__cvar_cache_clear(repo);
1128
14997dc5 1129 if (!repo->is_bare && recurse)
867f7c9b 1130 (void)git_submodule_foreach(repo, repo_reinit_submodule_fs, NULL);
14997dc5 1131
5173ea92
RB
1132 return error;
1133}
1134
dc34da6e 1135static int repo_write_template(
991a56c7
RB
1136 const char *git_dir,
1137 bool allow_overwrite,
1138 const char *file,
1139 mode_t mode,
662880ca 1140 bool hidden,
991a56c7 1141 const char *content)
dc34da6e
RB
1142{
1143 git_buf path = GIT_BUF_INIT;
991a56c7 1144 int fd, error = 0, flags;
dc34da6e
RB
1145
1146 if (git_buf_joinpath(&path, git_dir, file) < 0)
1147 return -1;
1148
991a56c7
RB
1149 if (allow_overwrite)
1150 flags = O_WRONLY | O_CREAT | O_TRUNC;
1151 else
1152 flags = O_WRONLY | O_CREAT | O_EXCL;
1153
1154 fd = p_open(git_buf_cstr(&path), flags, mode);
dc34da6e 1155
db628072
RB
1156 if (fd >= 0) {
1157 error = p_write(fd, content, strlen(content));
dc34da6e 1158
db628072
RB
1159 p_close(fd);
1160 }
1161 else if (errno != EEXIST)
1162 error = fd;
dc34da6e 1163
662880ca
RB
1164#ifdef GIT_WIN32
1165 if (!error && hidden) {
1166 if (p_hide_directory__w32(path.ptr) < 0)
1167 error = -1;
1168 }
1169#else
1170 GIT_UNUSED(hidden);
1171#endif
1172
dc34da6e 1173 git_buf_free(&path);
db628072
RB
1174
1175 if (error)
1176 giterr_set(GITERR_OS,
1177 "Failed to initialize repository with template '%s'", file);
1178
1179 return error;
dc34da6e
RB
1180}
1181
662880ca
RB
1182static int repo_write_gitlink(
1183 const char *in_dir, const char *to_repo)
4b8e27c8 1184{
662880ca
RB
1185 int error;
1186 git_buf buf = GIT_BUF_INIT;
1187 struct stat st;
1188
1189 git_path_dirname_r(&buf, to_repo);
1190 git_path_to_dir(&buf);
1191 if (git_buf_oom(&buf))
cb8a7961 1192 return -1;
a67a096a 1193
662880ca
RB
1194 /* don't write gitlink to natural workdir */
1195 if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 &&
1196 strcmp(in_dir, buf.ptr) == 0)
1197 {
1198 error = GIT_PASSTHROUGH;
1199 goto cleanup;
1200 }
1201
1202 if ((error = git_buf_joinpath(&buf, in_dir, DOT_GIT)) < 0)
1203 goto cleanup;
1204
1205 if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) {
1206 giterr_set(GITERR_REPOSITORY,
1207 "Cannot overwrite gitlink file into path '%s'", in_dir);
1208 error = GIT_EEXISTS;
1209 goto cleanup;
1210 }
1211
1212 git_buf_clear(&buf);
1213
1214 error = git_buf_printf(&buf, "%s %s", GIT_FILE_CONTENT_PREFIX, to_repo);
1215
1216 if (!error)
18f08264 1217 error = repo_write_template(in_dir, true, DOT_GIT, 0666, true, buf.ptr);
662880ca
RB
1218
1219cleanup:
1220 git_buf_free(&buf);
1221 return error;
1222}
1223
ca1b6e54
RB
1224static mode_t pick_dir_mode(git_repository_init_options *opts)
1225{
1226 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_UMASK)
18f08264 1227 return 0777;
ca1b6e54
RB
1228 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_GROUP)
1229 return (0775 | S_ISGID);
1230 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_ALL)
1231 return (0777 | S_ISGID);
1232 return opts->mode;
1233}
1234
662880ca
RB
1235#include "repo_template.h"
1236
1237static int repo_init_structure(
1238 const char *repo_dir,
1239 const char *work_dir,
1240 git_repository_init_options *opts)
1241{
ca1b6e54 1242 int error = 0;
662880ca 1243 repo_template_item *tpl;
ca1b6e54
RB
1244 bool external_tpl =
1245 ((opts->flags & GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) != 0);
1246 mode_t dmode = pick_dir_mode(opts);
662880ca
RB
1247
1248 /* Hide the ".git" directory */
17837602 1249#ifdef GIT_WIN32
2eb4edf5 1250 if ((opts->flags & GIT_REPOSITORY_INIT__HAS_DOTGIT) != 0) {
662880ca 1251 if (p_hide_directory__w32(repo_dir) < 0) {
cb8a7961
VM
1252 giterr_set(GITERR_REPOSITORY,
1253 "Failed to mark Git repository folder as hidden");
1254 return -1;
1255 }
17837602 1256 }
2eb4edf5
RB
1257#endif
1258
1259 /* Create the .git gitlink if appropriate */
1260 if ((opts->flags & GIT_REPOSITORY_INIT_BARE) == 0 &&
1261 (opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD) == 0)
1262 {
662880ca 1263 if (repo_write_gitlink(work_dir, repo_dir) < 0)
cb8a7961 1264 return -1;
97769280 1265 }
1c2c7c0d 1266
ca1b6e54
RB
1267 /* Copy external template if requested */
1268 if (external_tpl) {
0cd1c3bb
L
1269 git_config *cfg = NULL;
1270 const char *tdir = NULL;
1271 bool default_template = false;
a025907e
L
1272 git_buf template_buf = GIT_BUF_INIT;
1273
ca1b6e54
RB
1274 if (opts->template_path)
1275 tdir = opts->template_path;
0cd1c3bb 1276 else if ((error = git_config_open_default(&cfg)) >= 0) {
ca1b6e54 1277 error = git_config_get_string(&tdir, cfg, "init.templatedir");
ca1b6e54 1278 giterr_clear();
0cd1c3bb
L
1279 }
1280
1281 if (!tdir) {
1ca3e49f 1282 if (!(error = git_futils_find_template_dir(&template_buf)))
417472e3 1283 tdir = template_buf.ptr;
0cd1c3bb 1284 default_template = true;
662880ca 1285 }
ca1b6e54 1286
1ca3e49f
RB
1287 if (tdir)
1288 error = git_futils_cp_r(tdir, repo_dir,
1289 GIT_CPDIR_COPY_SYMLINKS | GIT_CPDIR_CHMOD_DIRS |
1290 GIT_CPDIR_SIMPLE_TO_MODE, dmode);
ca1b6e54 1291
0cd1c3bb
L
1292 git_buf_free(&template_buf);
1293 git_config_free(cfg);
1ca3e49f 1294
ca1b6e54 1295 if (error < 0) {
0cd1c3bb 1296 if (!default_template)
ca1b6e54
RB
1297 return error;
1298
1299 /* if template was default, ignore error and use internal */
1300 giterr_clear();
1301 external_tpl = false;
b7b1acfd 1302 error = 0;
ca1b6e54
RB
1303 }
1304 }
1305
1306 /* Copy internal template
1307 * - always ensure existence of dirs
1308 * - only create files if no external template was specified
1309 */
1310 for (tpl = repo_template; !error && tpl->path; ++tpl) {
1311 if (!tpl->content)
1312 error = git_futils_mkdir(
1313 tpl->path, repo_dir, dmode, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD);
1314 else if (!external_tpl) {
662880ca
RB
1315 const char *content = tpl->content;
1316
1317 if (opts->description && strcmp(tpl->path, GIT_DESC_FILE) == 0)
1318 content = opts->description;
1319
ca1b6e54
RB
1320 error = repo_write_template(
1321 repo_dir, false, tpl->path, tpl->mode, false, content);
662880ca 1322 }
dc34da6e
RB
1323 }
1324
ca1b6e54 1325 return error;
4b8e27c8 1326}
1327
3c42e4ef
RB
1328static int mkdir_parent(git_buf *buf, uint32_t mode, bool skip2)
1329{
0d1b094b
RB
1330 /* When making parent directories during repository initialization
1331 * don't try to set gid or grant world write access
1332 */
3c42e4ef 1333 return git_futils_mkdir(
0d1b094b 1334 buf->ptr, NULL, mode & ~(S_ISGID | 0002),
3c42e4ef
RB
1335 GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR |
1336 (skip2 ? GIT_MKDIR_SKIP_LAST2 : GIT_MKDIR_SKIP_LAST));
1337}
1338
662880ca
RB
1339static int repo_init_directories(
1340 git_buf *repo_path,
1341 git_buf *wd_path,
1342 const char *given_repo,
1343 git_repository_init_options *opts)
4b8e27c8 1344{
662880ca 1345 int error = 0;
3c42e4ef 1346 bool is_bare, add_dotgit, has_dotgit, natural_wd;
ca1b6e54 1347 mode_t dirmode;
932d1baf 1348
3c42e4ef
RB
1349 /* There are three possible rules for what we are allowed to create:
1350 * - MKPATH means anything we need
1351 * - MKDIR means just the .git directory and its parent and the workdir
1352 * - Neither means only the .git directory can be created
1353 *
1354 * There are 5 "segments" of path that we might need to deal with:
1355 * 1. The .git directory
1356 * 2. The parent of the .git directory
1357 * 3. Everything above the parent of the .git directory
1358 * 4. The working directory (often the same as #2)
1359 * 5. Everything above the working directory (often the same as #3)
1360 *
1361 * For all directories created, we start with the init_mode value for
1362 * permissions and then strip off bits in some cases:
1363 *
1364 * For MKPATH, we create #3 (and #5) paths without S_ISGID or S_IWOTH
1365 * For MKPATH and MKDIR, we create #2 (and #4) without S_ISGID
1366 * For all rules, we create #1 using the untouched init_mode
1367 */
1368
662880ca 1369 /* set up repo path */
4b8e27c8 1370
3c42e4ef
RB
1371 is_bare = ((opts->flags & GIT_REPOSITORY_INIT_BARE) != 0);
1372
662880ca
RB
1373 add_dotgit =
1374 (opts->flags & GIT_REPOSITORY_INIT_NO_DOTGIT_DIR) == 0 &&
3c42e4ef 1375 !is_bare &&
662880ca
RB
1376 git__suffixcmp(given_repo, "/" DOT_GIT) != 0 &&
1377 git__suffixcmp(given_repo, "/" GIT_DIR) != 0;
4b8e27c8 1378
662880ca
RB
1379 if (git_buf_joinpath(repo_path, given_repo, add_dotgit ? GIT_DIR : "") < 0)
1380 return -1;
693b23c0 1381
662880ca
RB
1382 has_dotgit = (git__suffixcmp(repo_path->ptr, "/" GIT_DIR) == 0);
1383 if (has_dotgit)
1384 opts->flags |= GIT_REPOSITORY_INIT__HAS_DOTGIT;
1385
1386 /* set up workdir path */
1387
3c42e4ef 1388 if (!is_bare) {
662880ca 1389 if (opts->workdir_path) {
ca1b6e54
RB
1390 if (git_path_join_unrooted(
1391 wd_path, opts->workdir_path, repo_path->ptr, NULL) < 0)
1392 return -1;
662880ca
RB
1393 } else if (has_dotgit) {
1394 if (git_path_dirname_r(wd_path, repo_path->ptr) < 0)
1395 return -1;
1396 } else {
1397 giterr_set(GITERR_REPOSITORY, "Cannot pick working directory"
1398 " for non-bare repository that isn't a '.git' directory");
1399 return -1;
1400 }
693b23c0 1401
662880ca
RB
1402 if (git_path_to_dir(wd_path) < 0)
1403 return -1;
1404 } else {
1405 git_buf_clear(wd_path);
1406 }
1407
1408 natural_wd =
1409 has_dotgit &&
1410 wd_path->size > 0 &&
1411 wd_path->size + strlen(GIT_DIR) == repo_path->size &&
1412 memcmp(repo_path->ptr, wd_path->ptr, wd_path->size) == 0;
1413 if (natural_wd)
1414 opts->flags |= GIT_REPOSITORY_INIT__NATURAL_WD;
1415
662880ca
RB
1416 /* create directories as needed / requested */
1417
ca1b6e54 1418 dirmode = pick_dir_mode(opts);
662880ca 1419
3c42e4ef
RB
1420 if ((opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) {
1421 /* create path #5 */
1422 if (wd_path->size > 0 &&
1423 (error = mkdir_parent(wd_path, dirmode, false)) < 0)
1424 return error;
1425
1426 /* create path #3 (if not the same as #5) */
1427 if (!natural_wd &&
1428 (error = mkdir_parent(repo_path, dirmode, has_dotgit)) < 0)
1429 return error;
1430 }
1431
1432 if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 ||
1433 (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0)
1434 {
1435 /* create path #4 */
1436 if (wd_path->size > 0 &&
1437 (error = git_futils_mkdir(
1438 wd_path->ptr, NULL, dirmode & ~S_ISGID,
1439 GIT_MKDIR_VERIFY_DIR)) < 0)
1440 return error;
1441
1442 /* create path #2 (if not the same as #4) */
1443 if (!natural_wd &&
1444 (error = git_futils_mkdir(
1445 repo_path->ptr, NULL, dirmode & ~S_ISGID,
1446 GIT_MKDIR_VERIFY_DIR | GIT_MKDIR_SKIP_LAST)) < 0)
1447 return error;
662880ca 1448 }
662880ca 1449
ca1b6e54
RB
1450 if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 ||
1451 (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0 ||
1452 has_dotgit)
1453 {
3c42e4ef 1454 /* create path #1 */
18f08264
RB
1455 error = git_futils_mkdir(repo_path->ptr, NULL, dirmode,
1456 GIT_MKDIR_VERIFY_DIR | ((dirmode & S_ISGID) ? GIT_MKDIR_CHMOD : 0));
662880ca 1457 }
ca1b6e54 1458
662880ca
RB
1459 /* prettify both directories now that they are created */
1460
1461 if (!error) {
1462 error = git_path_prettify_dir(repo_path, repo_path->ptr, NULL);
1463
1464 if (!error && wd_path->size > 0)
1465 error = git_path_prettify_dir(wd_path, wd_path->ptr, NULL);
1466 }
1467
1468 return error;
1469}
1470
1471static int repo_init_create_origin(git_repository *repo, const char *url)
1472{
1473 int error;
1474 git_remote *remote;
1475
29f27599 1476 if (!(error = git_remote_create(&remote, repo, GIT_REMOTE_ORIGIN, url))) {
662880ca
RB
1477 git_remote_free(remote);
1478 }
1479
1480 return error;
1481}
1482
1483int git_repository_init(
1484 git_repository **repo_out, const char *path, unsigned is_bare)
1485{
b4d13652 1486 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
662880ca 1487
662880ca
RB
1488 opts.flags = GIT_REPOSITORY_INIT_MKPATH; /* don't love this default */
1489 if (is_bare)
1490 opts.flags |= GIT_REPOSITORY_INIT_BARE;
1491
1492 return git_repository_init_ext(repo_out, path, &opts);
1493}
1494
1495int git_repository_init_ext(
c9fc4a6f 1496 git_repository **out,
662880ca
RB
1497 const char *given_repo,
1498 git_repository_init_options *opts)
1499{
1500 int error;
1501 git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT;
1502
c9fc4a6f 1503 assert(out && given_repo && opts);
662880ca 1504
c7231c45 1505 GITERR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options");
b4d13652 1506
662880ca
RB
1507 error = repo_init_directories(&repo_path, &wd_path, given_repo, opts);
1508 if (error < 0)
693b23c0 1509 goto cleanup;
662880ca
RB
1510
1511 if (valid_repository_path(&repo_path)) {
1512
1513 if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) {
1514 giterr_set(GITERR_REPOSITORY,
1515 "Attempt to reinitialize '%s'", given_repo);
1516 error = GIT_EEXISTS;
1517 goto cleanup;
1518 }
1519
1520 opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT;
1521
ca1b6e54 1522 error = repo_init_config(
14997dc5 1523 repo_path.ptr, wd_path.ptr, opts->flags, opts->mode);
662880ca
RB
1524
1525 /* TODO: reinitialize the templates */
1526 }
1527 else {
1528 if (!(error = repo_init_structure(
5173ea92 1529 repo_path.ptr, wd_path.ptr, opts)) &&
ca1b6e54 1530 !(error = repo_init_config(
14997dc5 1531 repo_path.ptr, wd_path.ptr, opts->flags, opts->mode)))
662880ca 1532 error = repo_init_create_head(
5173ea92 1533 repo_path.ptr, opts->initial_head);
cb8a7961 1534 }
662880ca
RB
1535 if (error < 0)
1536 goto cleanup;
1537
5173ea92 1538 error = git_repository_open(out, repo_path.ptr);
d2d6912e 1539
662880ca 1540 if (!error && opts->origin_url)
c9fc4a6f 1541 error = repo_init_create_origin(*out, opts->origin_url);
693b23c0 1542
1543cleanup:
662880ca
RB
1544 git_buf_free(&repo_path);
1545 git_buf_free(&wd_path);
1546
1547 return error;
40c44d2f 1548}
35502d2e 1549
c682886e 1550int git_repository_head_detached(git_repository *repo)
35502d2e
CMN
1551{
1552 git_reference *ref;
9462c471 1553 git_odb *odb = NULL;
cb8a7961 1554 int exists;
9462c471 1555
cb8a7961
VM
1556 if (git_repository_odb__weakptr(&odb, repo) < 0)
1557 return -1;
35502d2e 1558
cb8a7961
VM
1559 if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0)
1560 return -1;
35502d2e 1561
75abd2b9
MS
1562 if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1563 git_reference_free(ref);
35502d2e 1564 return 0;
75abd2b9 1565 }
35502d2e 1566
2508cc66 1567 exists = git_odb_exists(odb, git_reference_target(ref));
75abd2b9
MS
1568
1569 git_reference_free(ref);
cb8a7961 1570 return exists;
35502d2e
CMN
1571}
1572
3601c4bf 1573int git_repository_head(git_reference **head_out, git_repository *repo)
35502d2e 1574{
b1a3a70e 1575 git_reference *head;
8b05bea8 1576 int error;
1577
b1a3a70e 1578 if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
1579 return error;
1580
1581 if (git_reference_type(head) == GIT_REF_OID) {
1582 *head_out = head;
1583 return 0;
1584 }
1585
2508cc66 1586 error = git_reference_lookup_resolved(head_out, repo, git_reference_symbolic_target(head), -1);
b1a3a70e 1587 git_reference_free(head);
8b05bea8 1588
605da51a 1589 return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error;
3601c4bf 1590}
1591
605da51a 1592int git_repository_head_unborn(git_repository *repo)
3601c4bf 1593{
cb8a7961 1594 git_reference *ref = NULL;
3601c4bf 1595 int error;
1596
1597 error = git_repository_head(&ref, repo);
cb8a7961 1598 git_reference_free(ref);
35502d2e 1599
605da51a 1600 if (error == GIT_EUNBORNBRANCH)
cb8a7961 1601 return 1;
75abd2b9 1602
cb8a7961
VM
1603 if (error < 0)
1604 return -1;
1605
1606 return 0;
35502d2e 1607}
e0011be3 1608
0066955d 1609static int at_least_one_cb(const char *refname, void *payload)
41233c40 1610{
6091457e 1611 GIT_UNUSED(refname);
1612 GIT_UNUSED(payload);
41233c40 1613
6091457e 1614 return GIT_EUSER;
1615}
41233c40 1616
6091457e 1617static int repo_contains_no_reference(git_repository *repo)
1618{
ec24e542 1619 int error = git_reference_foreach_name(repo, &at_least_one_cb, NULL);
0f489fb2 1620
6091457e 1621 if (error == GIT_EUSER)
0f489fb2 1622 return 0;
ec24e542 1623
e976b56d
RB
1624 if (!error)
1625 return 1;
ec24e542 1626
e976b56d 1627 return error;
6091457e 1628}
75abd2b9 1629
6091457e 1630int git_repository_is_empty(git_repository *repo)
1631{
1632 git_reference *head = NULL;
42181836 1633 int is_empty = 0;
cb8a7961 1634
6091457e 1635 if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0)
cb8a7961
VM
1636 return -1;
1637
42181836
RB
1638 if (git_reference_type(head) == GIT_REF_SYMBOLIC)
1639 is_empty =
1640 (strcmp(git_reference_symbolic_target(head),
1641 GIT_REFS_HEADS_DIR "master") == 0) &&
1642 repo_contains_no_reference(repo);
6091457e 1643
6091457e 1644 git_reference_free(head);
42181836
RB
1645
1646 return is_empty;
41233c40
VM
1647}
1648
9462c471 1649const char *git_repository_path(git_repository *repo)
4a34b3a9 1650{
1651 assert(repo);
9462c471
VM
1652 return repo->path_repository;
1653}
4a34b3a9 1654
9462c471
VM
1655const char *git_repository_workdir(git_repository *repo)
1656{
1657 assert(repo);
602ee38b 1658
9462c471
VM
1659 if (repo->is_bare)
1660 return NULL;
602ee38b 1661
9462c471
VM
1662 return repo->workdir;
1663}
602ee38b 1664
991a56c7
RB
1665int git_repository_set_workdir(
1666 git_repository *repo, const char *workdir, int update_gitlink)
9462c471 1667{
991a56c7 1668 int error = 0;
b78fb64d 1669 git_buf path = GIT_BUF_INIT;
1670
9462c471 1671 assert(repo && workdir);
602ee38b 1672
b78fb64d 1673 if (git_path_prettify_dir(&path, workdir, NULL) < 0)
1674 return -1;
9462c471 1675
991a56c7
RB
1676 if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0)
1677 return 0;
9462c471 1678
991a56c7
RB
1679 if (update_gitlink) {
1680 git_config *config;
1681
1682 if (git_repository_config__weakptr(&config, repo) < 0)
1683 return -1;
1684
662880ca 1685 error = repo_write_gitlink(path.ptr, git_repository_path(repo));
991a56c7
RB
1686
1687 /* passthrough error means gitlink is unnecessary */
1688 if (error == GIT_PASSTHROUGH)
54b2a37a 1689 error = git_config_delete_entry(config, "core.worktree");
991a56c7
RB
1690 else if (!error)
1691 error = git_config_set_string(config, "core.worktree", path.ptr);
1692
1693 if (!error)
1694 error = git_config_set_bool(config, "core.bare", false);
1695 }
1696
1697 if (!error) {
1698 char *old_workdir = repo->workdir;
1699
1700 repo->workdir = git_buf_detach(&path);
1701 repo->is_bare = 0;
1702
1703 git__free(old_workdir);
1704 }
1705
1706 return error;
4a34b3a9 1707}
fa9bcd81 1708
1709int git_repository_is_bare(git_repository *repo)
1710{
1711 assert(repo);
1712 return repo->is_bare;
1713}
f917481e
RB
1714
1715int git_repository_head_tree(git_tree **tree, git_repository *repo)
1716{
5cec896a 1717 git_reference *head;
1718 git_object *obj;
1719 int error;
f917481e 1720
5cec896a 1721 if ((error = git_repository_head(&head, repo)) < 0)
1722 return error;
f917481e 1723
5cec896a 1724 if ((error = git_reference_peel(&obj, head, GIT_OBJ_TREE)) < 0)
1725 goto cleanup;
f917481e
RB
1726
1727 *tree = (git_tree *)obj;
5cec896a 1728
1729cleanup:
1730 git_reference_free(head);
1731 return error;
f917481e 1732}
074841ec 1733
074841ec
CMN
1734int git_repository_message(char *buffer, size_t len, git_repository *repo)
1735{
0ac349a9
VM
1736 git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
1737 struct stat st;
0ac349a9 1738 int error;
074841ec 1739
3d1c9f61
RB
1740 if (buffer != NULL)
1741 *buffer = '\0';
1742
632d8b23 1743 if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
0ac349a9 1744 return -1;
074841ec 1745
e9ca852e 1746 if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) {
074841ec
CMN
1747 if (errno == ENOENT)
1748 error = GIT_ENOTFOUND;
1a9e406c 1749 giterr_set(GITERR_OS, "Could not access message file");
0ac349a9 1750 }
e9ca852e
RB
1751 else if (buffer != NULL) {
1752 error = git_futils_readbuffer(&buf, git_buf_cstr(&path));
1753 git_buf_copy_cstr(buffer, len, &buf);
0ac349a9 1754 }
074841ec 1755
0ac349a9
VM
1756 git_buf_free(&path);
1757 git_buf_free(&buf);
074841ec 1758
e9ca852e
RB
1759 if (!error)
1760 error = (int)st.st_size + 1; /* add 1 for NUL byte */
1761
1762 return error;
074841ec
CMN
1763}
1764
1765int git_repository_message_remove(git_repository *repo)
1766{
0ac349a9
VM
1767 git_buf path = GIT_BUF_INIT;
1768 int error;
074841ec 1769
632d8b23 1770 if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
0ac349a9 1771 return -1;
074841ec
CMN
1772
1773 error = p_unlink(git_buf_cstr(&path));
1774 git_buf_free(&path);
1775
1776 return error;
1777}
47bfa0be
RB
1778
1779int git_repository_hashfile(
0cb16fe9
L
1780 git_oid *out,
1781 git_repository *repo,
1782 const char *path,
1783 git_otype type,
1784 const char *as_path)
47bfa0be
RB
1785{
1786 int error;
85d54812 1787 git_filter_list *fl = NULL;
b1127a30 1788 git_file fd = -1;
47bfa0be
RB
1789 git_off_t len;
1790 git_buf full_path = GIT_BUF_INIT;
1791
a13fb55a
RB
1792 assert(out && path && repo); /* as_path can be NULL */
1793
1794 /* At some point, it would be nice if repo could be NULL to just
1795 * apply filter rules defined in system and global files, but for
1796 * now that is not possible because git_filters_load() needs it.
1797 */
47bfa0be
RB
1798
1799 error = git_path_join_unrooted(
1800 &full_path, path, repo ? git_repository_workdir(repo) : NULL, NULL);
1801 if (error < 0)
1802 return error;
1803
1804 if (!as_path)
1805 as_path = path;
1806
1807 /* passing empty string for "as_path" indicated --no-filters */
1808 if (strlen(as_path) > 0) {
4b11f25a
RB
1809 error = git_filter_list_load(
1810 &fl, repo, NULL, as_path, GIT_FILTER_TO_ODB);
47bfa0be
RB
1811 if (error < 0)
1812 return error;
1813 } else {
1814 error = 0;
1815 }
1816
1817 /* at this point, error is a count of the number of loaded filters */
1818
1819 fd = git_futils_open_ro(full_path.ptr);
1820 if (fd < 0) {
1821 error = fd;
1822 goto cleanup;
1823 }
1824
1825 len = git_futils_filesize(fd);
1826 if (len < 0) {
75050223 1827 error = (int)len;
47bfa0be
RB
1828 goto cleanup;
1829 }
1830
1831 if (!git__is_sizet(len)) {
1832 giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
1833 error = -1;
1834 goto cleanup;
1835 }
1836
85d54812 1837 error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, fl);
47bfa0be
RB
1838
1839cleanup:
b1127a30
SS
1840 if (fd >= 0)
1841 p_close(fd);
85d54812 1842 git_filter_list_free(fl);
47bfa0be
RB
1843 git_buf_free(&full_path);
1844
1845 return error;
1846}
1847
44af67a8 1848static bool looks_like_a_branch(const char *refname)
1849{
1850 return git__prefixcmp(refname, GIT_REFS_HEADS_DIR) == 0;
1851}
1852
1853int git_repository_set_head(
1854 git_repository* repo,
1855 const char* refname)
1856{
1857 git_reference *ref,
1858 *new_head = NULL;
1859 int error;
1860
1861 assert(repo && refname);
1862
1863 error = git_reference_lookup(&ref, repo, refname);
1864 if (error < 0 && error != GIT_ENOTFOUND)
1865 return error;
1866
1867 if (!error) {
1868 if (git_reference_is_branch(ref))
2508cc66 1869 error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, git_reference_name(ref), 1);
44af67a8 1870 else
2508cc66 1871 error = git_repository_set_head_detached(repo, git_reference_target(ref));
44af67a8 1872 } else if (looks_like_a_branch(refname))
2508cc66 1873 error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname, 1);
44af67a8 1874
1875 git_reference_free(ref);
1876 git_reference_free(new_head);
1877 return error;
1878}
1879
4ebe38bd 1880int git_repository_set_head_detached(
1881 git_repository* repo,
1882 const git_oid* commitish)
1883{
1884 int error;
1885 git_object *object,
1886 *peeled = NULL;
1887 git_reference *new_head = NULL;
1888
1889 assert(repo && commitish);
1890
1891 if ((error = git_object_lookup(&object, repo, commitish, GIT_OBJ_ANY)) < 0)
1892 return error;
1893
1894 if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0)
1895 goto cleanup;
1896
2508cc66 1897 error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), 1);
4ebe38bd 1898
1899cleanup:
1900 git_object_free(object);
1901 git_object_free(peeled);
1902 git_reference_free(new_head);
1903 return error;
1904}
1905
3f4c3072 1906int git_repository_detach_head(
1907 git_repository* repo)
1908{
1909 git_reference *old_head = NULL,
1910 *new_head = NULL;
1911 git_object *object = NULL;
8b05bea8 1912 int error;
3f4c3072 1913
1914 assert(repo);
1915
8b05bea8 1916 if ((error = git_repository_head(&old_head, repo)) < 0)
1917 return error;
3f4c3072 1918
2508cc66 1919 if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJ_COMMIT)) < 0)
3f4c3072 1920 goto cleanup;
1921
2508cc66 1922 error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head), 1);
3f4c3072 1923
1924cleanup:
1925 git_object_free(object);
1926 git_reference_free(old_head);
1927 git_reference_free(new_head);
1928 return error;
1929}
632d8b23 1930
31966d20 1931/**
1932 * Loosely ported from git.git
1933 * https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh#L198-289
1934 */
632d8b23
ET
1935int git_repository_state(git_repository *repo)
1936{
1937 git_buf repo_path = GIT_BUF_INIT;
1938 int state = GIT_REPOSITORY_STATE_NONE;
1939
1940 assert(repo);
1941
1942 if (git_buf_puts(&repo_path, repo->path_repository) < 0)
1943 return -1;
1944
31966d20 1945 if (git_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE))
1946 state = GIT_REPOSITORY_STATE_REBASE_INTERACTIVE;
1947 else if (git_path_contains_dir(&repo_path, GIT_REBASE_MERGE_DIR))
1948 state = GIT_REPOSITORY_STATE_REBASE_MERGE;
1949 else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_REBASING_FILE))
1950 state = GIT_REPOSITORY_STATE_REBASE;
1951 else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_APPLYING_FILE))
1952 state = GIT_REPOSITORY_STATE_APPLY_MAILBOX;
1953 else if (git_path_contains_dir(&repo_path, GIT_REBASE_APPLY_DIR))
1954 state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE;
1955 else if (git_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE))
632d8b23
ET
1956 state = GIT_REPOSITORY_STATE_MERGE;
1957 else if(git_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE))
1958 state = GIT_REPOSITORY_STATE_REVERT;
1959 else if(git_path_contains_file(&repo_path, GIT_CHERRY_PICK_HEAD_FILE))
1960 state = GIT_REPOSITORY_STATE_CHERRY_PICK;
31966d20 1961 else if(git_path_contains_file(&repo_path, GIT_BISECT_LOG_FILE))
1962 state = GIT_REPOSITORY_STATE_BISECT;
632d8b23
ET
1963
1964 git_buf_free(&repo_path);
1965 return state;
1966}
93d8f77f
BS
1967
1968int git_repository_is_shallow(git_repository *repo)
1969{
1970 git_buf path = GIT_BUF_INIT;
1971 struct stat st;
6f0b8142 1972 int error;
93d8f77f
BS
1973
1974 git_buf_joinpath(&path, repo->path_repository, "shallow");
6f0b8142
BS
1975 error = git_path_lstat(path.ptr, &st);
1976 git_buf_free(&path);
93d8f77f 1977
6f0b8142 1978 if (error == GIT_ENOTFOUND)
93d8f77f 1979 return 0;
6f0b8142
BS
1980 if (error < 0)
1981 return -1;
93d8f77f
BS
1982 return st.st_size == 0 ? 0 : 1;
1983}