]> git.proxmox.com Git - libgit2.git/blame - src/repository.c
branch: restrict branch deletion for worktrees
[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 */
7784bcbb 7#include <ctype.h>
3315782c 8
44908fe7 9#include "git2/object.h"
d00d5464 10#include "git2/refdb.h"
1384b688 11#include "git2/sys/repository.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"
83634d38 19#include "sysdir.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"
62d38a1d 29#include "annotated_commit.h"
4d99c4cf 30#include "submodule.h"
8c8d726e 31#include "worktree.h"
4d99c4cf
BP
32
33GIT__USE_STRMAP
34#include "strmap.h"
9282e921 35
c2c81615
PK
36#ifdef GIT_WIN32
37# include "win32/w32_util.h"
38#endif
39
cb3269c9
PS
40static const struct {
41 git_repository_item_t parent;
42 const char *name;
43 bool directory;
44} items[] = {
45 { GIT_REPOSITORY_ITEM_GITDIR, NULL, true },
46 { GIT_REPOSITORY_ITEM_WORKDIR, NULL, true },
47 { GIT_REPOSITORY_ITEM_COMMONDIR, NULL, true },
48 { GIT_REPOSITORY_ITEM_GITDIR, "index", false },
49 { GIT_REPOSITORY_ITEM_COMMONDIR, "objects", true },
50 { GIT_REPOSITORY_ITEM_COMMONDIR, "refs", true },
51 { GIT_REPOSITORY_ITEM_COMMONDIR, "packed-refs", false },
52 { GIT_REPOSITORY_ITEM_COMMONDIR, "remotes", true },
53 { GIT_REPOSITORY_ITEM_COMMONDIR, "config", false },
54 { GIT_REPOSITORY_ITEM_COMMONDIR, "info", true },
55 { GIT_REPOSITORY_ITEM_COMMONDIR, "hooks", true },
56 { GIT_REPOSITORY_ITEM_COMMONDIR, "logs", true },
57 { GIT_REPOSITORY_ITEM_GITDIR, "modules", true },
58 { GIT_REPOSITORY_ITEM_COMMONDIR, "worktrees", true }
59};
60
16c73d38
CMN
61static int check_repositoryformatversion(git_config *config);
62
c09fd54e
PS
63#define GIT_COMMONDIR_FILE "commondir"
64
7784bcbb 65#define GIT_FILE_CONTENT_PREFIX "gitdir:"
6a01b6bd 66
28990938 67#define GIT_BRANCH_MASTER "master"
68
29e948de 69#define GIT_REPO_VERSION 0
691aa968 70
4196dd8e
ET
71git_buf git_repository__reserved_names_win32[] = {
72 { DOT_GIT, 0, CONST_STRLEN(DOT_GIT) },
73 { GIT_DIR_SHORTNAME, 0, CONST_STRLEN(GIT_DIR_SHORTNAME) }
74};
75size_t git_repository__reserved_names_win32_len = 2;
76
77git_buf git_repository__reserved_names_posix[] = {
78 { DOT_GIT, 0, CONST_STRLEN(DOT_GIT) },
79};
80size_t git_repository__reserved_names_posix_len = 1;
a64119e3 81
e976b56d 82static void set_odb(git_repository *repo, git_odb *odb)
9462c471 83{
e976b56d
RB
84 if (odb) {
85 GIT_REFCOUNT_OWN(odb, repo);
86 GIT_REFCOUNT_INC(odb);
87 }
88
89 if ((odb = git__swap(repo->_odb, odb)) != NULL) {
90 GIT_REFCOUNT_OWN(odb, NULL);
91 git_odb_free(odb);
eb2f3b47 92 }
9462c471 93}
691aa968 94
e976b56d 95static void set_refdb(git_repository *repo, git_refdb *refdb)
d00d5464 96{
e976b56d
RB
97 if (refdb) {
98 GIT_REFCOUNT_OWN(refdb, repo);
99 GIT_REFCOUNT_INC(refdb);
100 }
101
102 if ((refdb = git__swap(repo->_refdb, refdb)) != NULL) {
103 GIT_REFCOUNT_OWN(refdb, NULL);
104 git_refdb_free(refdb);
d00d5464
ET
105 }
106}
107
e976b56d 108static void set_config(git_repository *repo, git_config *config)
9462c471 109{
e976b56d
RB
110 if (config) {
111 GIT_REFCOUNT_OWN(config, repo);
112 GIT_REFCOUNT_INC(config);
113 }
114
115 if ((config = git__swap(repo->_config, config)) != NULL) {
116 GIT_REFCOUNT_OWN(config, NULL);
117 git_config_free(config);
eb2f3b47 118 }
e976b56d
RB
119
120 git_repository__cvar_cache_clear(repo);
691aa968
VM
121}
122
e976b56d 123static void set_index(git_repository *repo, git_index *index)
6fd195d7 124{
e976b56d
RB
125 if (index) {
126 GIT_REFCOUNT_OWN(index, repo);
127 GIT_REFCOUNT_INC(index);
128 }
129
130 if ((index = git__swap(repo->_index, index)) != NULL) {
131 GIT_REFCOUNT_OWN(index, NULL);
132 git_index_free(index);
9462c471 133 }
e0011be3
VM
134}
135
879458e7 136void git_repository__cleanup(git_repository *repo)
e0011be3 137{
879458e7 138 assert(repo);
6fd195d7 139
4d99c4cf 140 git_repository_submodule_cache_clear(repo);
879458e7 141 git_cache_clear(&repo->objects);
73b51450 142 git_attr_cache_flush(repo);
6fd195d7 143
e976b56d
RB
144 set_config(repo, NULL);
145 set_index(repo, NULL);
146 set_odb(repo, NULL);
147 set_refdb(repo, NULL);
879458e7
VM
148}
149
150void git_repository_free(git_repository *repo)
151{
4196dd8e
ET
152 size_t i;
153
879458e7
VM
154 if (repo == NULL)
155 return;
156
157 git_repository__cleanup(repo);
158
159 git_cache_free(&repo->objects);
3eadfecd 160
114f5a6c 161 git_diff_driver_registry_free(repo->diff_drivers);
3eadfecd 162 repo->diff_drivers = NULL;
9462c471 163
4196dd8e
ET
164 for (i = 0; i < repo->reserved_names.size; i++)
165 git_buf_free(git_array_get(repo->reserved_names, i));
78db0239 166 git_array_clear(repo->reserved_names);
4196dd8e 167
78db0239 168 git__free(repo->path_gitlink);
53607868 169 git__free(repo->path_repository);
c09fd54e 170 git__free(repo->commondir);
53607868 171 git__free(repo->workdir);
bade5194 172 git__free(repo->namespace);
659cf202
CMN
173 git__free(repo->ident_name);
174 git__free(repo->ident_email);
53607868 175
6de9b2ee 176 git__memzero(repo, sizeof(*repo));
9462c471 177 git__free(repo);
6fd195d7
VM
178}
179
9462c471
VM
180/*
181 * Git repository open methods
182 *
183 * Open a repository object from its path
184 */
c09fd54e 185static bool valid_repository_path(git_buf *repository_path, git_buf *common_path)
5ad739e8 186{
c09fd54e
PS
187 /* Check if we have a separate commondir (e.g. we have a
188 * worktree) */
189 if (git_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) {
190 git_buf common_link = GIT_BUF_INIT;
191 git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE);
192
193 git_futils_readbuffer(&common_link, common_link.ptr);
194 git_buf_rtrim(&common_link);
195
196 if (git_path_is_relative(common_link.ptr)) {
197 git_buf_joinpath(common_path, repository_path->ptr, common_link.ptr);
198 } else {
199 git_buf_swap(common_path, &common_link);
200 }
201
202 git_buf_free(&common_link);
203 }
204 else {
205 git_buf_set(common_path, repository_path->ptr, repository_path->size);
206 }
207
208 /* Make sure the commondir path always has a trailing * slash */
209 if (git_buf_rfind(common_path, '/') != (ssize_t)common_path->size - 1)
210 git_buf_putc(common_path, '/');
5ad739e8 211
97769280 212 /* Ensure HEAD file exists */
1a481123 213 if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false)
cb8a7961 214 return false;
5ad739e8 215
c09fd54e
PS
216 /* Check files in common dir */
217 if (git_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false)
218 return false;
219 if (git_path_contains_dir(common_path, GIT_REFS_DIR) == false)
cb8a7961 220 return false;
5ad739e8 221
cb8a7961 222 return true;
5ad739e8
VM
223}
224
51d00446 225static git_repository *repository_alloc(void)
3315782c 226{
3e9e6cda 227 git_repository *repo = git__calloc(1, sizeof(git_repository));
3315782c 228
4196dd8e
ET
229 if (repo == NULL ||
230 git_cache_init(&repo->objects) < 0)
231 goto on_error;
232
233 git_array_init_to_size(repo->reserved_names, 4);
234 if (!repo->reserved_names.ptr)
235 goto on_error;
3315782c 236
f2c25d18
VM
237 /* set all the entries in the cvar cache to `unset` */
238 git_repository__cvar_cache_clear(repo);
239
6fd195d7 240 return repo;
4196dd8e
ET
241
242on_error:
243 if (repo)
244 git_cache_free(&repo->objects);
245
246 git__free(repo);
247 return NULL;
6fd195d7
VM
248}
249
7cc3c920
JW
250int git_repository_new(git_repository **out)
251{
770aca94
ET
252 git_repository *repo;
253
254 *out = repo = repository_alloc();
255 GITERR_CHECK_ALLOC(repo);
256
257 repo->is_bare = 1;
79ab3ef6 258 repo->is_worktree = 0;
770aca94 259
7cc3c920
JW
260 return 0;
261}
262
29c4cb09 263static int load_config_data(git_repository *repo, const git_config *config)
ec3c7a16 264{
cb8a7961 265 int is_bare;
ec3c7a16 266
d3e9c4a5 267 /* Try to figure out if it's bare, default to non-bare if it's not set */
29e948de 268 if (git_config_get_bool(&is_bare, config, "core.bare") < 0)
d3e9c4a5
CMN
269 repo->is_bare = 0;
270 else
271 repo->is_bare = is_bare;
c94785a9 272
cb8a7961 273 return 0;
9462c471 274}
ec3c7a16 275
29c4cb09 276static int load_workdir(git_repository *repo, git_config *config, git_buf *parent_path)
9462c471 277{
7784bcbb 278 int error;
9a97f49e 279 git_config_entry *ce;
9f77b3f6 280 git_buf worktree = GIT_BUF_INIT;
ec3c7a16 281
97769280 282 if (repo->is_bare)
cb8a7961 283 return 0;
ec3c7a16 284
9f77b3f6
RB
285 if ((error = git_config__lookup_entry(
286 &ce, config, "core.worktree", false)) < 0)
287 return error;
ec3c7a16 288
9f77b3f6
RB
289 if (ce && ce->value) {
290 if ((error = git_path_prettify_dir(
291 &worktree, ce->value, repo->path_repository)) < 0)
9a97f49e 292 goto cleanup;
9f77b3f6
RB
293
294 repo->workdir = git_buf_detach(&worktree);
5f4a61ae 295 }
9f77b3f6
RB
296 else if (parent_path && git_path_isdir(parent_path->ptr))
297 repo->workdir = git_buf_detach(parent_path);
7784bcbb 298 else {
9f77b3f6 299 if (git_path_dirname_r(&worktree, repo->path_repository) < 0 ||
9a97f49e
CMN
300 git_path_to_dir(&worktree) < 0) {
301 error = -1;
302 goto cleanup;
303 }
9f77b3f6
RB
304
305 repo->workdir = git_buf_detach(&worktree);
7784bcbb
RB
306 }
307
308 GITERR_CHECK_ALLOC(repo->workdir);
9a97f49e
CMN
309cleanup:
310 git_config_entry_free(ce);
311 return error;
ec3c7a16
VM
312}
313
7784bcbb
RB
314/*
315 * This function returns furthest offset into path where a ceiling dir
316 * is found, so we can stop processing the path at that point.
317 *
318 * Note: converting this to use git_bufs instead of GIT_PATH_MAX buffers on
319 * the stack could remove directories name limits, but at the cost of doing
320 * repeated malloc/frees inside the loop below, so let's not do it now.
321 */
b118f647 322static size_t find_ceiling_dir_offset(
7784bcbb
RB
323 const char *path,
324 const char *ceiling_directories)
325{
326 char buf[GIT_PATH_MAX + 1];
327 char buf2[GIT_PATH_MAX + 1];
328 const char *ceil, *sep;
44ef8b1b 329 size_t len, max_len = 0, min_len;
7784bcbb
RB
330
331 assert(path);
332
44ef8b1b 333 min_len = (size_t)(git_path_root(path) + 1);
7784bcbb
RB
334
335 if (ceiling_directories == NULL || min_len == 0)
b118f647 336 return min_len;
7784bcbb
RB
337
338 for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) {
339 for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);
340 len = sep - ceil;
341
44ef8b1b 342 if (len == 0 || len >= sizeof(buf) || git_path_root(ceil) == -1)
7784bcbb
RB
343 continue;
344
345 strncpy(buf, ceil, len);
346 buf[len] = '\0';
347
348 if (p_realpath(buf, buf2) == NULL)
349 continue;
350
351 len = strlen(buf2);
352 if (len > 0 && buf2[len-1] == '/')
353 buf[--len] = '\0';
354
355 if (!strncmp(path, buf2, len) &&
3fe046cf 356 (path[len] == '/' || !path[len]) &&
7784bcbb
RB
357 len > max_len)
358 {
359 max_len = len;
360 }
361 }
362
b118f647 363 return (max_len <= min_len ? min_len : max_len);
7784bcbb
RB
364}
365
366/*
367 * Read the contents of `file_path` and set `path_out` to the repo dir that
368 * it points to. Before calling, set `path_out` to the base directory that
369 * should be used if the contents of `file_path` are a relative path.
370 */
371static int read_gitfile(git_buf *path_out, const char *file_path)
372{
373 int error = 0;
374 git_buf file = GIT_BUF_INIT;
375 size_t prefix_len = strlen(GIT_FILE_CONTENT_PREFIX);
376
377 assert(path_out && file_path);
378
379 if (git_futils_readbuffer(&file, file_path) < 0)
380 return -1;
381
382 git_buf_rtrim(&file);
6b415f62
RB
383 /* apparently on Windows, some people use backslashes in paths */
384 git_path_mkposix(file.ptr);
7784bcbb 385
662880ca
RB
386 if (git_buf_len(&file) <= prefix_len ||
387 memcmp(git_buf_cstr(&file), GIT_FILE_CONTENT_PREFIX, prefix_len) != 0)
7784bcbb 388 {
6b415f62 389 giterr_set(GITERR_REPOSITORY,
909d5494 390 "the `.git` file at '%s' is malformed", file_path);
7784bcbb
RB
391 error = -1;
392 }
393 else if ((error = git_path_dirname_r(path_out, file_path)) >= 0) {
662880ca 394 const char *gitlink = git_buf_cstr(&file) + prefix_len;
0f49200c 395 while (*gitlink && git__isspace(*gitlink)) gitlink++;
6b415f62 396
662880ca
RB
397 error = git_path_prettify_dir(
398 path_out, gitlink, git_buf_cstr(path_out));
7784bcbb
RB
399 }
400
401 git_buf_free(&file);
402 return error;
403}
404
405static int find_repo(
406 git_buf *repo_path,
407 git_buf *parent_path,
4196dd8e 408 git_buf *link_path,
c09fd54e 409 git_buf *common_path,
7784bcbb
RB
410 const char *start_path,
411 uint32_t flags,
412 const char *ceiling_dirs)
691aa968 413{
7784bcbb
RB
414 int error;
415 git_buf path = GIT_BUF_INIT;
2b490284 416 git_buf repo_link = GIT_BUF_INIT;
c09fd54e 417 git_buf common_link = GIT_BUF_INIT;
7784bcbb
RB
418 struct stat st;
419 dev_t initial_device = 0;
ed577134
JT
420 int min_iterations;
421 bool in_dot_git;
b118f647 422 size_t ceiling_offset = 0;
7784bcbb
RB
423
424 git_buf_free(repo_path);
425
2b490284
JT
426 error = git_path_prettify(&path, start_path, NULL);
427 if (error < 0)
7784bcbb
RB
428 return error;
429
ed577134
JT
430 /* in_dot_git toggles each loop:
431 * /a/b/c/.git, /a/b/c, /a/b/.git, /a/b, /a/.git, /a
39c6fca3
JT
432 * With GIT_REPOSITORY_OPEN_BARE or GIT_REPOSITORY_OPEN_NO_DOTGIT, we
433 * assume we started with /a/b/c.git and don't append .git the first
434 * time through.
ed577134
JT
435 * min_iterations indicates the number of iterations left before going
436 * further counts as a search. */
39c6fca3 437 if (flags & (GIT_REPOSITORY_OPEN_BARE | GIT_REPOSITORY_OPEN_NO_DOTGIT)) {
ed577134
JT
438 in_dot_git = true;
439 min_iterations = 1;
440 } else {
441 in_dot_git = false;
442 min_iterations = 2;
443 }
7784bcbb 444
2b490284 445 for (;;) {
39c6fca3 446 if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT)) {
2b490284
JT
447 if (!in_dot_git) {
448 error = git_buf_joinpath(&path, path.ptr, DOT_GIT);
449 if (error < 0)
39c6fca3 450 break;
2b490284 451 }
39c6fca3
JT
452 in_dot_git = !in_dot_git;
453 }
7784bcbb 454
7784bcbb
RB
455 if (p_stat(path.ptr, &st) == 0) {
456 /* check that we have not crossed device boundaries */
457 if (initial_device == 0)
458 initial_device = st.st_dev;
459 else if (st.st_dev != initial_device &&
2b490284 460 !(flags & GIT_REPOSITORY_OPEN_CROSS_FS))
7784bcbb
RB
461 break;
462
463 if (S_ISDIR(st.st_mode)) {
c09fd54e 464 if (valid_repository_path(&path, &common_link)) {
7784bcbb
RB
465 git_path_to_dir(&path);
466 git_buf_set(repo_path, path.ptr, path.size);
c09fd54e
PS
467
468 if (common_path)
469 git_buf_swap(&common_link, common_path);
470
7784bcbb
RB
471 break;
472 }
473 }
0f316096 474 else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) {
2b490284
JT
475 error = read_gitfile(&repo_link, path.ptr);
476 if (error < 0)
7784bcbb 477 break;
c09fd54e 478 if (valid_repository_path(&repo_link, &common_link)) {
2b490284
JT
479 git_buf_swap(repo_path, &repo_link);
480
481 if (link_path)
482 error = git_buf_put(link_path, path.ptr, path.size);
c09fd54e
PS
483 if (common_path)
484 git_buf_swap(&common_link, common_path);
7784bcbb 485 }
2b490284 486 break;
7784bcbb
RB
487 }
488 }
489
2b490284
JT
490 /* Move up one directory. If we're in_dot_git, we'll search the
491 * parent itself next. If we're !in_dot_git, we'll search .git
492 * in the parent directory next (added at the top of the loop). */
7784bcbb
RB
493 if (git_path_dirname_r(&path, path.ptr) < 0) {
494 error = -1;
495 break;
496 }
497
ed577134
JT
498 /* Once we've checked the directory (and .git if applicable),
499 * find the ceiling for a search. */
500 if (min_iterations && (--min_iterations == 0))
501 ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs);
2b490284
JT
502
503 /* Check if we should stop searching here. */
504 if (min_iterations == 0
505 && (path.ptr[ceiling_offset] == 0
506 || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))
507 break;
7784bcbb
RB
508 }
509
3fe046cf 510 if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
fa6420f7 511 if (!git_buf_len(repo_path))
7784bcbb
RB
512 git_buf_clear(parent_path);
513 else {
514 git_path_dirname_r(parent_path, path.ptr);
515 git_path_to_dir(parent_path);
516 }
517 if (git_buf_oom(parent_path))
518 return -1;
519 }
520
2b490284
JT
521 /* If we didn't find the repository, and we don't have any other error
522 * to report, report that. */
fa6420f7 523 if (!git_buf_len(repo_path) && !error) {
cb8a7961 524 giterr_set(GITERR_REPOSITORY,
909d5494 525 "could not find repository from '%s'", start_path);
904b67e6 526 error = GIT_ENOTFOUND;
97769280 527 }
691aa968 528
2b490284
JT
529 git_buf_free(&path);
530 git_buf_free(&repo_link);
c09fd54e 531 git_buf_free(&common_link);
7784bcbb
RB
532 return error;
533}
534
a442ed68
VM
535int git_repository_open_bare(
536 git_repository **repo_ptr,
537 const char *bare_path)
538{
539 int error;
c09fd54e 540 git_buf path = GIT_BUF_INIT, common_path = GIT_BUF_INIT;
a442ed68
VM
541 git_repository *repo = NULL;
542
543 if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0)
544 return error;
545
c09fd54e 546 if (!valid_repository_path(&path, &common_path)) {
a442ed68 547 git_buf_free(&path);
c09fd54e 548 git_buf_free(&common_path);
909d5494 549 giterr_set(GITERR_REPOSITORY, "path is not a repository: %s", bare_path);
a442ed68
VM
550 return GIT_ENOTFOUND;
551 }
552
553 repo = repository_alloc();
554 GITERR_CHECK_ALLOC(repo);
555
556 repo->path_repository = git_buf_detach(&path);
557 GITERR_CHECK_ALLOC(repo->path_repository);
c09fd54e
PS
558 repo->commondir = git_buf_detach(&common_path);
559 GITERR_CHECK_ALLOC(repo->commondir);
a442ed68
VM
560
561 /* of course we're bare! */
562 repo->is_bare = 1;
79ab3ef6 563 repo->is_worktree = 0;
a442ed68
VM
564 repo->workdir = NULL;
565
566 *repo_ptr = repo;
567 return 0;
568}
569
0dd98b69
JT
570static int _git_repository_open_ext_from_env(
571 git_repository **out,
572 const char *start_path)
573{
574 git_repository *repo = NULL;
575 git_index *index = NULL;
576 git_odb *odb = NULL;
577 git_buf dir_buf = GIT_BUF_INIT;
578 git_buf ceiling_dirs_buf = GIT_BUF_INIT;
579 git_buf across_fs_buf = GIT_BUF_INIT;
580 git_buf index_file_buf = GIT_BUF_INIT;
581 git_buf namespace_buf = GIT_BUF_INIT;
582 git_buf object_dir_buf = GIT_BUF_INIT;
583 git_buf alts_buf = GIT_BUF_INIT;
584 git_buf work_tree_buf = GIT_BUF_INIT;
585 git_buf common_dir_buf = GIT_BUF_INIT;
586 const char *ceiling_dirs = NULL;
587 unsigned flags = 0;
588 int error;
589
590 if (!start_path) {
591 error = git__getenv(&dir_buf, "GIT_DIR");
592 if (error == GIT_ENOTFOUND) {
593 giterr_clear();
594 start_path = ".";
595 } else if (error < 0)
596 goto error;
597 else {
598 start_path = git_buf_cstr(&dir_buf);
599 flags |= GIT_REPOSITORY_OPEN_NO_SEARCH;
600 flags |= GIT_REPOSITORY_OPEN_NO_DOTGIT;
601 }
602 }
603
604 error = git__getenv(&ceiling_dirs_buf, "GIT_CEILING_DIRECTORIES");
605 if (error == GIT_ENOTFOUND)
606 giterr_clear();
607 else if (error < 0)
608 goto error;
609 else
610 ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf);
611
612 error = git__getenv(&across_fs_buf, "GIT_DISCOVERY_ACROSS_FILESYSTEM");
613 if (error == GIT_ENOTFOUND)
614 giterr_clear();
615 else if (error < 0)
616 goto error;
617 else {
618 int across_fs = 0;
619 error = git_config_parse_bool(&across_fs, git_buf_cstr(&across_fs_buf));
620 if (error < 0)
621 goto error;
622 if (across_fs)
623 flags |= GIT_REPOSITORY_OPEN_CROSS_FS;
624 }
625
626 error = git__getenv(&index_file_buf, "GIT_INDEX_FILE");
627 if (error == GIT_ENOTFOUND)
628 giterr_clear();
629 else if (error < 0)
630 goto error;
631 else {
632 error = git_index_open(&index, git_buf_cstr(&index_file_buf));
633 if (error < 0)
634 goto error;
635 }
636
637 error = git__getenv(&namespace_buf, "GIT_NAMESPACE");
638 if (error == GIT_ENOTFOUND)
639 giterr_clear();
640 else if (error < 0)
641 goto error;
642
643 error = git__getenv(&object_dir_buf, "GIT_OBJECT_DIRECTORY");
644 if (error == GIT_ENOTFOUND)
645 giterr_clear();
646 else if (error < 0)
647 goto error;
648 else {
649 error = git_odb_open(&odb, git_buf_cstr(&object_dir_buf));
650 if (error < 0)
651 goto error;
652 }
653
654 error = git__getenv(&work_tree_buf, "GIT_WORK_TREE");
655 if (error == GIT_ENOTFOUND)
656 giterr_clear();
657 else if (error < 0)
658 goto error;
659 else {
660 giterr_set(GITERR_INVALID, "GIT_WORK_TREE unimplemented");
661 error = GIT_ERROR;
662 goto error;
663 }
664
665 error = git__getenv(&work_tree_buf, "GIT_COMMON_DIR");
666 if (error == GIT_ENOTFOUND)
667 giterr_clear();
668 else if (error < 0)
669 goto error;
670 else {
671 giterr_set(GITERR_INVALID, "GIT_COMMON_DIR unimplemented");
672 error = GIT_ERROR;
673 goto error;
674 }
675
676 error = git_repository_open_ext(&repo, start_path, flags, ceiling_dirs);
677 if (error < 0)
678 goto error;
679
680 if (odb)
681 git_repository_set_odb(repo, odb);
682
683 error = git__getenv(&alts_buf, "GIT_ALTERNATE_OBJECT_DIRECTORIES");
c9e967a1 684 if (error == GIT_ENOTFOUND) {
0dd98b69 685 giterr_clear();
c9e967a1
JT
686 error = 0;
687 } else if (error < 0)
0dd98b69
JT
688 goto error;
689 else {
690 const char *end;
691 char *alt, *sep;
692 if (!odb) {
693 error = git_repository_odb(&odb, repo);
694 if (error < 0)
695 goto error;
696 }
697
698 end = git_buf_cstr(&alts_buf) + git_buf_len(&alts_buf);
699 for (sep = alt = alts_buf.ptr; sep != end; alt = sep+1) {
700 for (sep = alt; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++)
701 ;
702 if (*sep)
703 *sep = '\0';
704 error = git_odb_add_disk_alternate(odb, alt);
705 if (error < 0)
706 goto error;
707 }
708 }
709
c9e967a1
JT
710 if (git_buf_len(&namespace_buf)) {
711 error = git_repository_set_namespace(repo, git_buf_cstr(&namespace_buf));
712 if (error < 0)
713 goto error;
714 }
0dd98b69
JT
715
716 git_repository_set_index(repo, index);
717
718 if (out) {
719 *out = repo;
720 goto success;
721 }
722error:
723 git_repository_free(repo);
724success:
725 git_odb_free(odb);
726 git_index_free(index);
727 git_buf_free(&common_dir_buf);
728 git_buf_free(&work_tree_buf);
729 git_buf_free(&alts_buf);
730 git_buf_free(&object_dir_buf);
731 git_buf_free(&namespace_buf);
732 git_buf_free(&index_file_buf);
733 git_buf_free(&across_fs_buf);
734 git_buf_free(&ceiling_dirs_buf);
735 git_buf_free(&dir_buf);
736 return error;
737}
738
7784bcbb
RB
739int git_repository_open_ext(
740 git_repository **repo_ptr,
741 const char *start_path,
c9fc4a6f 742 unsigned int flags,
7784bcbb
RB
743 const char *ceiling_dirs)
744{
745 int error;
4196dd8e 746 git_buf path = GIT_BUF_INIT, parent = GIT_BUF_INIT,
c09fd54e 747 link_path = GIT_BUF_INIT, common_path = GIT_BUF_INIT;
7784bcbb 748 git_repository *repo;
16c73d38 749 git_config *config = NULL;
7784bcbb 750
0dd98b69
JT
751 if (flags & GIT_REPOSITORY_OPEN_FROM_ENV)
752 return _git_repository_open_ext_from_env(repo_ptr, start_path);
753
662880ca
RB
754 if (repo_ptr)
755 *repo_ptr = NULL;
7784bcbb 756
4196dd8e 757 error = find_repo(
c09fd54e 758 &path, &parent, &link_path, &common_path, start_path, flags, ceiling_dirs);
4196dd8e 759
662880ca 760 if (error < 0 || !repo_ptr)
7784bcbb
RB
761 return error;
762
e52ed7a5 763 repo = repository_alloc();
cb8a7961 764 GITERR_CHECK_ALLOC(repo);
691aa968 765
7784bcbb 766 repo->path_repository = git_buf_detach(&path);
cb8a7961 767 GITERR_CHECK_ALLOC(repo->path_repository);
691aa968 768
4196dd8e
ET
769 if (link_path.size) {
770 repo->path_gitlink = git_buf_detach(&link_path);
771 GITERR_CHECK_ALLOC(repo->path_gitlink);
772 }
c09fd54e
PS
773 if (common_path.size) {
774 repo->commondir = git_buf_detach(&common_path);
775 GITERR_CHECK_ALLOC(repo->commondir);
776 }
4196dd8e 777
79ab3ef6
PS
778 if (repo->path_gitlink && repo->commondir && strcmp(repo->path_gitlink, repo->commondir))
779 repo->is_worktree = 1;
780
16c73d38
CMN
781 /*
782 * We'd like to have the config, but git doesn't particularly
783 * care if it's not there, so we need to deal with that.
784 */
785
786 error = git_repository_config_snapshot(&config, repo);
787 if (error < 0 && error != GIT_ENOTFOUND)
788 goto cleanup;
789
790 if (config && (error = check_repositoryformatversion(config)) < 0)
791 goto cleanup;
792
3fe046cf
RB
793 if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0)
794 repo->is_bare = 1;
2b52a0bf 795 else {
2b52a0bf 796
16c73d38
CMN
797 if (config &&
798 ((error = load_config_data(repo, config)) < 0 ||
6a8f3fa8 799 (error = load_workdir(repo, config, &parent)) < 0))
16c73d38 800 goto cleanup;
7784bcbb 801 }
691aa968 802
16c73d38 803cleanup:
146f5c75 804 git_buf_free(&parent);
16c73d38
CMN
805 git_config_free(config);
806
807 if (error < 0)
808 git_repository_free(repo);
809 else
810 *repo_ptr = repo;
2b52a0bf
RB
811
812 return error;
7784bcbb 813}
97769280 814
7784bcbb
RB
815int git_repository_open(git_repository **repo_out, const char *path)
816{
817 return git_repository_open_ext(
818 repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL);
819}
820
8c8d726e
PS
821int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *wt)
822{
823 git_buf path = GIT_BUF_INIT;
824 git_repository *repo = NULL;
825 int len, err;
826
827 assert(repo_out && wt);
828
829 *repo_out = NULL;
830 len = strlen(wt->gitlink_path);
831
832 if (len <= 4 || strcasecmp(wt->gitlink_path + len - 4, ".git")) {
833 err = -1;
834 goto out;
835 }
836
837 if ((err = git_buf_set(&path, wt->gitlink_path, len - 4)) < 0)
838 goto out;
839
840 if ((err = git_repository_open(&repo, path.ptr)) < 0)
841 goto out;
842
843 *repo_out = repo;
844
845out:
846 git_buf_free(&path);
847
848 return err;
849}
850
6782245e
CMN
851int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb)
852{
853 git_repository *repo;
854
855 repo = repository_alloc();
856 GITERR_CHECK_ALLOC(repo);
857
858 git_repository_set_odb(repo, odb);
859 *repo_out = repo;
860
861 return 0;
862}
863
7784bcbb 864int git_repository_discover(
7a3bd1e7 865 git_buf *out,
7784bcbb
RB
866 const char *start_path,
867 int across_fs,
868 const char *ceiling_dirs)
869{
7784bcbb 870 uint32_t flags = across_fs ? GIT_REPOSITORY_OPEN_CROSS_FS : 0;
7784bcbb 871
7a3bd1e7 872 assert(start_path);
7784bcbb 873
7a3bd1e7 874 git_buf_sanitize(out);
7784bcbb 875
c09fd54e 876 return find_repo(out, NULL, NULL, NULL, start_path, flags, ceiling_dirs);
691aa968
VM
877}
878
9462c471 879static int load_config(
7784bcbb
RB
880 git_config **out,
881 git_repository *repo,
882 const char *global_config_path,
4258d483 883 const char *xdg_config_path,
8c7c5fa5
CMN
884 const char *system_config_path,
885 const char *programdata_path)
b22d1479 886{
cc6b4162 887 int error;
97769280 888 git_buf config_path = GIT_BUF_INIT;
9462c471 889 git_config *cfg = NULL;
b22d1479 890
9462c471 891 assert(repo && out);
07ff8817 892
cc6b4162
RB
893 if ((error = git_config_new(&cfg)) < 0)
894 return error;
b22d1479 895
4292837d 896 error = git_repository_item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG);
cc6b4162 897 if (error < 0)
cb8a7961 898 goto on_error;
97769280 899
cc6b4162
RB
900 if ((error = git_config_add_file_ondisk(
901 cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0 &&
902 error != GIT_ENOTFOUND)
cb8a7961
VM
903 goto on_error;
904
905 git_buf_free(&config_path);
b22d1479 906
cc6b4162
RB
907 if (global_config_path != NULL &&
908 (error = git_config_add_file_ondisk(
909 cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, 0)) < 0 &&
910 error != GIT_ENOTFOUND)
911 goto on_error;
8b4f9b17 912
cc6b4162
RB
913 if (xdg_config_path != NULL &&
914 (error = git_config_add_file_ondisk(
915 cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, 0)) < 0 &&
916 error != GIT_ENOTFOUND)
917 goto on_error;
b22d1479 918
cc6b4162
RB
919 if (system_config_path != NULL &&
920 (error = git_config_add_file_ondisk(
921 cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, 0)) < 0 &&
922 error != GIT_ENOTFOUND)
923 goto on_error;
9ba9e513 924
8c7c5fa5
CMN
925 if (programdata_path != NULL &&
926 (error = git_config_add_file_ondisk(
927 cfg, programdata_path, GIT_CONFIG_LEVEL_PROGRAMDATA, 0)) < 0 &&
928 error != GIT_ENOTFOUND)
929 goto on_error;
930
38f7d026
RB
931 giterr_clear(); /* clear any lingering ENOTFOUND errors */
932
9462c471 933 *out = cfg;
cb8a7961 934 return 0;
b22d1479 935
cb8a7961
VM
936on_error:
937 git_buf_free(&config_path);
9462c471
VM
938 git_config_free(cfg);
939 *out = NULL;
cc6b4162 940 return error;
b22d1479
CMN
941}
942
53607868 943static const char *path_unless_empty(git_buf *buf)
40fe5fbe 944{
53607868
RB
945 return git_buf_len(buf) > 0 ? git_buf_cstr(buf) : NULL;
946}
8b4f9b17 947
53607868
RB
948int git_repository_config__weakptr(git_config **out, git_repository *repo)
949{
950 int error = 0;
40fe5fbe 951
53607868
RB
952 if (repo->_config == NULL) {
953 git_buf global_buf = GIT_BUF_INIT;
954 git_buf xdg_buf = GIT_BUF_INIT;
955 git_buf system_buf = GIT_BUF_INIT;
8c7c5fa5 956 git_buf programdata_buf = GIT_BUF_INIT;
53607868
RB
957 git_config *config;
958
ee550477
CMN
959 git_config_find_global(&global_buf);
960 git_config_find_xdg(&xdg_buf);
961 git_config_find_system(&system_buf);
8c7c5fa5 962 git_config_find_programdata(&programdata_buf);
53607868 963
a4b75dcf
CMN
964 /* If there is no global file, open a backend for it anyway */
965 if (git_buf_len(&global_buf) == 0)
966 git_config__global_location(&global_buf);
967
53607868
RB
968 error = load_config(
969 &config, repo,
970 path_unless_empty(&global_buf),
971 path_unless_empty(&xdg_buf),
8c7c5fa5
CMN
972 path_unless_empty(&system_buf),
973 path_unless_empty(&programdata_buf));
53607868
RB
974 if (!error) {
975 GIT_REFCOUNT_OWN(config, repo);
976
e976b56d 977 config = git__compare_and_swap(&repo->_config, NULL, config);
53607868
RB
978 if (config != NULL) {
979 GIT_REFCOUNT_OWN(config, NULL);
980 git_config_free(config);
981 }
982 }
97769280
RB
983
984 git_buf_free(&global_buf);
a8918418 985 git_buf_free(&xdg_buf);
97769280 986 git_buf_free(&system_buf);
4f971852 987 git_buf_free(&programdata_buf);
9462c471 988 }
40fe5fbe 989
9462c471 990 *out = repo->_config;
53607868 991 return error;
40fe5fbe
CMN
992}
993
9462c471 994int git_repository_config(git_config **out, git_repository *repo)
fd0574e5 995{
cb8a7961
VM
996 if (git_repository_config__weakptr(out, repo) < 0)
997 return -1;
fd0574e5 998
cb8a7961
VM
999 GIT_REFCOUNT_INC(*out);
1000 return 0;
9462c471
VM
1001}
1002
ac99d86b
CMN
1003int git_repository_config_snapshot(git_config **out, git_repository *repo)
1004{
b1914c36 1005 int error;
ac99d86b
CMN
1006 git_config *weak;
1007
b1914c36
RB
1008 if ((error = git_repository_config__weakptr(&weak, repo)) < 0)
1009 return error;
ac99d86b
CMN
1010
1011 return git_config_snapshot(out, weak);
1012}
1013
9462c471
VM
1014void git_repository_set_config(git_repository *repo, git_config *config)
1015{
1016 assert(repo && config);
e976b56d 1017 set_config(repo, config);
9462c471
VM
1018}
1019
1020int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
1021{
53607868
RB
1022 int error = 0;
1023
9462c471
VM
1024 assert(repo && out);
1025
1026 if (repo->_odb == NULL) {
97769280 1027 git_buf odb_path = GIT_BUF_INIT;
53607868 1028 git_odb *odb;
9462c471 1029
c5f3da96
PS
1030 if ((error = git_repository_item_path(&odb_path, repo,
1031 GIT_REPOSITORY_ITEM_OBJECTS)) < 0)
3dbd9a0e 1032 return error;
9462c471 1033
53607868
RB
1034 error = git_odb_open(&odb, odb_path.ptr);
1035 if (!error) {
1036 GIT_REFCOUNT_OWN(odb, repo);
cb8a7961 1037
e976b56d 1038 odb = git__compare_and_swap(&repo->_odb, NULL, odb);
53607868
RB
1039 if (odb != NULL) {
1040 GIT_REFCOUNT_OWN(odb, NULL);
1041 git_odb_free(odb);
1042 }
1043 }
9462c471 1044
53607868 1045 git_buf_free(&odb_path);
9462c471 1046 }
fd0574e5 1047
9462c471 1048 *out = repo->_odb;
53607868 1049 return error;
fd0574e5
RG
1050}
1051
9462c471 1052int git_repository_odb(git_odb **out, git_repository *repo)
6fd195d7 1053{
cb8a7961
VM
1054 if (git_repository_odb__weakptr(out, repo) < 0)
1055 return -1;
1795f879 1056
cb8a7961
VM
1057 GIT_REFCOUNT_INC(*out);
1058 return 0;
9462c471 1059}
6fd195d7 1060
9462c471
VM
1061void git_repository_set_odb(git_repository *repo, git_odb *odb)
1062{
1063 assert(repo && odb);
e976b56d 1064 set_odb(repo, odb);
9462c471
VM
1065}
1066
d00d5464
ET
1067int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo)
1068{
53607868
RB
1069 int error = 0;
1070
d00d5464
ET
1071 assert(out && repo);
1072
1073 if (repo->_refdb == NULL) {
53607868 1074 git_refdb *refdb;
d00d5464 1075
53607868
RB
1076 error = git_refdb_open(&refdb, repo);
1077 if (!error) {
1078 GIT_REFCOUNT_OWN(refdb, repo);
d00d5464 1079
e976b56d 1080 refdb = git__compare_and_swap(&repo->_refdb, NULL, refdb);
53607868
RB
1081 if (refdb != NULL) {
1082 GIT_REFCOUNT_OWN(refdb, NULL);
1083 git_refdb_free(refdb);
1084 }
1085 }
d00d5464
ET
1086 }
1087
1088 *out = repo->_refdb;
53607868 1089 return error;
d00d5464
ET
1090}
1091
1092int git_repository_refdb(git_refdb **out, git_repository *repo)
1093{
1094 if (git_repository_refdb__weakptr(out, repo) < 0)
1095 return -1;
1096
1097 GIT_REFCOUNT_INC(*out);
1098 return 0;
1099}
1100
1101void git_repository_set_refdb(git_repository *repo, git_refdb *refdb)
1102{
53607868 1103 assert(repo && refdb);
e976b56d 1104 set_refdb(repo, refdb);
d00d5464
ET
1105}
1106
9462c471
VM
1107int git_repository_index__weakptr(git_index **out, git_repository *repo)
1108{
53607868
RB
1109 int error = 0;
1110
9462c471
VM
1111 assert(out && repo);
1112
9462c471 1113 if (repo->_index == NULL) {
97769280 1114 git_buf index_path = GIT_BUF_INIT;
53607868 1115 git_index *index;
9462c471 1116
3dbd9a0e
JG
1117 if ((error = git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE)) < 0)
1118 return error;
9462c471 1119
53607868
RB
1120 error = git_index_open(&index, index_path.ptr);
1121 if (!error) {
1122 GIT_REFCOUNT_OWN(index, repo);
cb8a7961 1123
e976b56d 1124 index = git__compare_and_swap(&repo->_index, NULL, index);
53607868
RB
1125 if (index != NULL) {
1126 GIT_REFCOUNT_OWN(index, NULL);
1127 git_index_free(index);
1128 }
9462c471 1129
53607868
RB
1130 error = git_index_set_caps(repo->_index, GIT_INDEXCAP_FROM_OWNER);
1131 }
da825c92 1132
53607868 1133 git_buf_free(&index_path);
9462c471
VM
1134 }
1135
9462c471 1136 *out = repo->_index;
53607868 1137 return error;
9462c471 1138}
1795f879 1139
9462c471
VM
1140int git_repository_index(git_index **out, git_repository *repo)
1141{
cb8a7961
VM
1142 if (git_repository_index__weakptr(out, repo) < 0)
1143 return -1;
9462c471 1144
cb8a7961
VM
1145 GIT_REFCOUNT_INC(*out);
1146 return 0;
3315782c
VM
1147}
1148
9462c471
VM
1149void git_repository_set_index(git_repository *repo, git_index *index)
1150{
fa8ca519 1151 assert(repo);
e976b56d 1152 set_index(repo, index);
9462c471
VM
1153}
1154
bade5194
VM
1155int git_repository_set_namespace(git_repository *repo, const char *namespace)
1156{
1157 git__free(repo->namespace);
1158
1159 if (namespace == NULL) {
1160 repo->namespace = NULL;
1161 return 0;
1162 }
1163
1164 return (repo->namespace = git__strdup(namespace)) ? 0 : -1;
1165}
1166
1167const char *git_repository_get_namespace(git_repository *repo)
1168{
1169 return repo->namespace;
1170}
1171
4196dd8e
ET
1172#ifdef GIT_WIN32
1173static int reserved_names_add8dot3(git_repository *repo, const char *path)
a64119e3 1174{
4196dd8e
ET
1175 char *name = git_win32_path_8dot3_name(path);
1176 const char *def = GIT_DIR_SHORTNAME;
526f91f5 1177 const char *def_dot_git = DOT_GIT;
4196dd8e 1178 size_t name_len, def_len = CONST_STRLEN(GIT_DIR_SHORTNAME);
526f91f5 1179 size_t def_dot_git_len = CONST_STRLEN(DOT_GIT);
4196dd8e 1180 git_buf *buf;
a64119e3 1181
4196dd8e
ET
1182 if (!name)
1183 return 0;
1184
1185 name_len = strlen(name);
1186
526f91f5
L
1187 if ((name_len == def_len && memcmp(name, def, def_len) == 0) ||
1188 (name_len == def_dot_git_len && memcmp(name, def_dot_git, def_dot_git_len) == 0)) {
4196dd8e
ET
1189 git__free(name);
1190 return 0;
1191 }
1192
1193 if ((buf = git_array_alloc(repo->reserved_names)) == NULL)
1194 return -1;
1195
1196 git_buf_attach(buf, name, name_len);
1197 return true;
1198}
1199
1200bool git_repository__reserved_names(
1201 git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs)
1202{
1203 GIT_UNUSED(include_ntfs);
1204
1205 if (repo->reserved_names.size == 0) {
1206 git_buf *buf;
1207 size_t i;
1208
1209 /* Add the static defaults */
1210 for (i = 0; i < git_repository__reserved_names_win32_len; i++) {
1211 if ((buf = git_array_alloc(repo->reserved_names)) == NULL)
1212 goto on_error;
1213
1214 buf->ptr = git_repository__reserved_names_win32[i].ptr;
1215 buf->size = git_repository__reserved_names_win32[i].size;
1216 }
1217
538dfc88
ET
1218 /* Try to add any repo-specific reserved names - the gitlink file
1219 * within a submodule or the repository (if the repository directory
1220 * is beneath the workdir). These are typically `.git`, but should
1221 * be protected in case they are not. Note, repo and workdir paths
1222 * are always prettified to end in `/`, so a prefixcmp is safe.
1223 */
a64119e3 1224 if (!repo->is_bare) {
538dfc88
ET
1225 int (*prefixcmp)(const char *, const char *);
1226 int error, ignorecase;
a64119e3 1227
538dfc88
ET
1228 error = git_repository__cvar(
1229 &ignorecase, repo, GIT_CVAR_IGNORECASE);
1230 prefixcmp = (error || ignorecase) ? git__prefixcmp_icase :
1231 git__prefixcmp;
1232
1233 if (repo->path_gitlink &&
1234 reserved_names_add8dot3(repo, repo->path_gitlink) < 0)
1235 goto on_error;
1236
1237 if (repo->path_repository &&
1238 prefixcmp(repo->path_repository, repo->workdir) == 0 &&
1239 reserved_names_add8dot3(repo, repo->path_repository) < 0)
4196dd8e 1240 goto on_error;
a64119e3 1241 }
a64119e3
ET
1242 }
1243
4196dd8e
ET
1244 *out = repo->reserved_names.ptr;
1245 *outlen = repo->reserved_names.size;
1246
1247 return true;
1248
1249 /* Always give good defaults, even on OOM */
1250on_error:
1251 *out = git_repository__reserved_names_win32;
1252 *outlen = git_repository__reserved_names_win32_len;
1253
1254 return false;
a64119e3 1255}
4196dd8e
ET
1256#else
1257bool git_repository__reserved_names(
1258 git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs)
1259{
1260 GIT_UNUSED(repo);
1261
1262 if (include_ntfs) {
1263 *out = git_repository__reserved_names_win32;
1264 *outlen = git_repository__reserved_names_win32_len;
1265 } else {
1266 *out = git_repository__reserved_names_posix;
1267 *outlen = git_repository__reserved_names_posix_len;
1268 }
1269
1270 return true;
1271}
1272#endif
a64119e3 1273
2c227b8b 1274static int check_repositoryformatversion(git_config *config)
40c44d2f 1275{
99e11cdd 1276 int version, error;
5663e61a 1277
99e11cdd
CMN
1278 error = git_config_get_int32(&version, config, "core.repositoryformatversion");
1279 /* git ignores this if the config variable isn't there */
1280 if (error == GIT_ENOTFOUND)
1281 return 0;
1282
1283 if (error < 0)
cb8a7961 1284 return -1;
5663e61a 1285
29e948de 1286 if (GIT_REPO_VERSION < version) {
cb8a7961 1287 giterr_set(GITERR_REPOSITORY,
909d5494 1288 "unsupported repository version %d. Only versions up to %d are supported.",
29e948de 1289 version, GIT_REPO_VERSION);
cb8a7961
VM
1290 return -1;
1291 }
5663e61a 1292
cb8a7961 1293 return 0;
5663e61a 1294}
1295
854b5c70 1296int git_repository_create_head(const char *git_dir, const char *ref_name)
e1f8cad0 1297{
97769280 1298 git_buf ref_path = GIT_BUF_INIT;
9462c471 1299 git_filebuf ref = GIT_FILEBUF_INIT;
662880ca 1300 const char *fmt;
9462c471 1301
cb8a7961 1302 if (git_buf_joinpath(&ref_path, git_dir, GIT_HEAD_FILE) < 0 ||
1d3a8aeb 1303 git_filebuf_open(&ref, ref_path.ptr, 0, GIT_REFS_FILE_MODE) < 0)
662880ca
RB
1304 goto fail;
1305
1306 if (!ref_name)
1307 ref_name = GIT_BRANCH_MASTER;
1308
74a24005 1309 if (git__prefixcmp(ref_name, GIT_REFS_DIR) == 0)
662880ca
RB
1310 fmt = "ref: %s\n";
1311 else
74a24005 1312 fmt = "ref: " GIT_REFS_HEADS_DIR "%s\n";
662880ca
RB
1313
1314 if (git_filebuf_printf(&ref, fmt, ref_name) < 0 ||
1d3a8aeb 1315 git_filebuf_commit(&ref) < 0)
662880ca 1316 goto fail;
9462c471 1317
97769280 1318 git_buf_free(&ref_path);
cb8a7961 1319 return 0;
662880ca
RB
1320
1321fail:
1322 git_buf_free(&ref_path);
1323 git_filebuf_cleanup(&ref);
1324 return -1;
9462c471
VM
1325}
1326
fac66990 1327static bool is_chmod_supported(const char *file_path)
1328{
1329 struct stat st1, st2;
fac66990 1330
1331 if (p_stat(file_path, &st1) < 0)
1332 return false;
1333
1334 if (p_chmod(file_path, st1.st_mode ^ S_IXUSR) < 0)
1335 return false;
1336
1337 if (p_stat(file_path, &st2) < 0)
1338 return false;
1339
6b7991e2 1340 return (st1.st_mode != st2.st_mode);
fac66990 1341}
1342
693b23c0 1343static bool is_filesystem_case_insensitive(const char *gitdir_path)
1344{
1345 git_buf path = GIT_BUF_INIT;
6b7991e2 1346 int is_insensitive = -1;
693b23c0 1347
6b7991e2
RB
1348 if (!git_buf_joinpath(&path, gitdir_path, "CoNfIg"))
1349 is_insensitive = git_path_exists(git_buf_cstr(&path));
693b23c0 1350
693b23c0 1351 git_buf_free(&path);
6b7991e2 1352 return is_insensitive;
693b23c0 1353}
1354
ca1b6e54
RB
1355static bool are_symlinks_supported(const char *wd_path)
1356{
1357 git_buf path = GIT_BUF_INIT;
1358 int fd;
1359 struct stat st;
6b7991e2 1360 int symlinks_supported = -1;
ca1b6e54 1361
1d3a8aeb 1362 if ((fd = git_futils_mktmp(&path, wd_path, 0666)) < 0 ||
ca1b6e54
RB
1363 p_close(fd) < 0 ||
1364 p_unlink(path.ptr) < 0 ||
1365 p_symlink("testing", path.ptr) < 0 ||
1366 p_lstat(path.ptr, &st) < 0)
6b7991e2 1367 symlinks_supported = false;
ca1b6e54 1368 else
6b7991e2 1369 symlinks_supported = (S_ISLNK(st.st_mode) != 0);
ca1b6e54
RB
1370
1371 (void)p_unlink(path.ptr);
1372 git_buf_free(&path);
1373
6b7991e2
RB
1374 return symlinks_supported;
1375}
1376
270160b9 1377static int create_empty_file(const char *path, mode_t mode)
1378{
1379 int fd;
1380
1381 if ((fd = p_creat(path, mode)) < 0) {
909d5494 1382 giterr_set(GITERR_OS, "error while creating '%s'", path);
270160b9 1383 return -1;
1384 }
1385
1386 if (p_close(fd) < 0) {
909d5494 1387 giterr_set(GITERR_OS, "error while closing '%s'", path);
270160b9 1388 return -1;
1389 }
1390
1391 return 0;
1392}
1393
14997dc5
RB
1394static int repo_local_config(
1395 git_config **out,
1396 git_buf *config_dir,
1397 git_repository *repo,
1398 const char *repo_dir)
9462c471 1399{
ca1b6e54 1400 int error = 0;
14997dc5
RB
1401 git_config *parent;
1402 const char *cfg_path;
9462c471 1403
14997dc5 1404 if (git_buf_joinpath(config_dir, repo_dir, GIT_CONFIG_FILENAME_INREPO) < 0)
cb8a7961 1405 return -1;
14997dc5 1406 cfg_path = git_buf_cstr(config_dir);
9462c471 1407
14997dc5 1408 /* make LOCAL config if missing */
5173ea92
RB
1409 if (!git_path_isfile(cfg_path) &&
1410 (error = create_empty_file(cfg_path, GIT_CONFIG_FILE_MODE)) < 0)
14997dc5 1411 return error;
270160b9 1412
14997dc5
RB
1413 /* if no repo, just open that file directly */
1414 if (!repo)
1415 return git_config_open_ondisk(out, cfg_path);
1416
1417 /* otherwise, open parent config and get that level */
1418 if ((error = git_repository_config__weakptr(&parent, repo)) < 0)
1419 return error;
1420
1421 if (git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL) < 0) {
5173ea92
RB
1422 giterr_clear();
1423
1424 if (!(error = git_config_add_file_ondisk(
1425 parent, cfg_path, GIT_CONFIG_LEVEL_LOCAL, false)))
14997dc5 1426 error = git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL);
cb8a7961 1427 }
9462c471 1428
14997dc5
RB
1429 git_config_free(parent);
1430
1431 return error;
1432}
1433
1434static int repo_init_fs_configs(
1435 git_config *cfg,
1436 const char *cfg_path,
1437 const char *repo_dir,
1438 const char *work_dir,
1439 bool update_ignorecase)
1440{
1441 int error = 0;
1442
1443 if (!work_dir)
1444 work_dir = repo_dir;
1445
1446 if ((error = git_config_set_bool(
1447 cfg, "core.filemode", is_chmod_supported(cfg_path))) < 0)
1448 return error;
1449
1450 if (!are_symlinks_supported(work_dir)) {
1451 if ((error = git_config_set_bool(cfg, "core.symlinks", false)) < 0)
1452 return error;
1453 } else if (git_config_delete_entry(cfg, "core.symlinks") < 0)
1454 giterr_clear();
2c227b8b 1455
14997dc5
RB
1456 if (update_ignorecase) {
1457 if (is_filesystem_case_insensitive(repo_dir)) {
1458 if ((error = git_config_set_bool(cfg, "core.ignorecase", true)) < 0)
1459 return error;
1460 } else if (git_config_delete_entry(cfg, "core.ignorecase") < 0)
1461 giterr_clear();
1462 }
662880ca 1463
af302aca 1464#ifdef GIT_USE_ICONV
14997dc5
RB
1465 if ((error = git_config_set_bool(
1466 cfg, "core.precomposeunicode",
43a04135 1467 git_path_does_fs_decompose_unicode(work_dir))) < 0)
14997dc5 1468 return error;
43a04135 1469 /* on non-iconv platforms, don't even set core.precomposeunicode */
6b7991e2
RB
1470#endif
1471
14997dc5
RB
1472 return 0;
1473}
7623b1b6 1474
14997dc5
RB
1475static int repo_init_config(
1476 const char *repo_dir,
1477 const char *work_dir,
1478 uint32_t flags,
1479 uint32_t mode)
1480{
1481 int error = 0;
bc737620 1482 git_buf cfg_path = GIT_BUF_INIT, worktree_path = GIT_BUF_INIT;
14997dc5
RB
1483 git_config *config = NULL;
1484 bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
1485 bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
1486
1487 if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0)
1488 goto cleanup;
1489
1490 if (is_reinit && (error = check_repositoryformatversion(config)) < 0)
1491 goto cleanup;
1492
1493#define SET_REPO_CONFIG(TYPE, NAME, VAL) do { \
1494 if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \
1495 goto cleanup; } while (0)
1496
1497 SET_REPO_CONFIG(bool, "core.bare", is_bare);
1498 SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION);
1499
1500 if ((error = repo_init_fs_configs(
1501 config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0)
1502 goto cleanup;
5173ea92 1503
6b7991e2
RB
1504 if (!is_bare) {
1505 SET_REPO_CONFIG(bool, "core.logallrefupdates", true);
ca1b6e54 1506
bc737620
JM
1507 if (!(flags & GIT_REPOSITORY_INIT__NATURAL_WD)) {
1508 if ((error = git_buf_sets(&worktree_path, work_dir)) < 0)
1509 goto cleanup;
1510
1511 if ((flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK))
1512 if ((error = git_path_make_relative(&worktree_path, repo_dir)) < 0)
1513 goto cleanup;
1514
1515 SET_REPO_CONFIG(string, "core.worktree", worktree_path.ptr);
1516 } else if (is_reinit) {
54b2a37a 1517 if (git_config_delete_entry(config, "core.worktree") < 0)
89cd5708 1518 giterr_clear();
ca1b6e54 1519 }
ca1b6e54
RB
1520 }
1521
5173ea92 1522 if (mode == GIT_REPOSITORY_INIT_SHARED_GROUP) {
662880ca
RB
1523 SET_REPO_CONFIG(int32, "core.sharedrepository", 1);
1524 SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true);
ca1b6e54 1525 }
5173ea92 1526 else if (mode == GIT_REPOSITORY_INIT_SHARED_ALL) {
662880ca
RB
1527 SET_REPO_CONFIG(int32, "core.sharedrepository", 2);
1528 SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true);
1529 }
9462c471 1530
ca1b6e54 1531cleanup:
14997dc5 1532 git_buf_free(&cfg_path);
bc737620 1533 git_buf_free(&worktree_path);
9462c471 1534 git_config_free(config);
662880ca 1535
ca1b6e54 1536 return error;
d2d6912e 1537}
e1f8cad0 1538
867f7c9b 1539static int repo_reinit_submodule_fs(git_submodule *sm, const char *n, void *p)
5173ea92 1540{
14997dc5
RB
1541 git_repository *smrepo = NULL;
1542 GIT_UNUSED(n); GIT_UNUSED(p);
5173ea92 1543
14997dc5 1544 if (git_submodule_open(&smrepo, sm) < 0 ||
867f7c9b 1545 git_repository_reinit_filesystem(smrepo, true) < 0)
14997dc5
RB
1546 giterr_clear();
1547 git_repository_free(smrepo);
5173ea92 1548
14997dc5
RB
1549 return 0;
1550}
5173ea92 1551
867f7c9b 1552int git_repository_reinit_filesystem(git_repository *repo, int recurse)
14997dc5
RB
1553{
1554 int error = 0;
1555 git_buf path = GIT_BUF_INIT;
1556 git_config *config = NULL;
1557 const char *repo_dir = git_repository_path(repo);
5173ea92 1558
14997dc5
RB
1559 if (!(error = repo_local_config(&config, &path, repo, repo_dir)))
1560 error = repo_init_fs_configs(
1561 config, path.ptr, repo_dir, git_repository_workdir(repo), true);
5173ea92 1562
14997dc5
RB
1563 git_config_free(config);
1564 git_buf_free(&path);
5173ea92 1565
5173ea92
RB
1566 git_repository__cvar_cache_clear(repo);
1567
14997dc5 1568 if (!repo->is_bare && recurse)
867f7c9b 1569 (void)git_submodule_foreach(repo, repo_reinit_submodule_fs, NULL);
14997dc5 1570
5173ea92
RB
1571 return error;
1572}
1573
dc34da6e 1574static int repo_write_template(
991a56c7
RB
1575 const char *git_dir,
1576 bool allow_overwrite,
1577 const char *file,
1578 mode_t mode,
662880ca 1579 bool hidden,
991a56c7 1580 const char *content)
dc34da6e
RB
1581{
1582 git_buf path = GIT_BUF_INIT;
991a56c7 1583 int fd, error = 0, flags;
dc34da6e
RB
1584
1585 if (git_buf_joinpath(&path, git_dir, file) < 0)
1586 return -1;
1587
991a56c7
RB
1588 if (allow_overwrite)
1589 flags = O_WRONLY | O_CREAT | O_TRUNC;
1590 else
1591 flags = O_WRONLY | O_CREAT | O_EXCL;
1592
1593 fd = p_open(git_buf_cstr(&path), flags, mode);
dc34da6e 1594
db628072
RB
1595 if (fd >= 0) {
1596 error = p_write(fd, content, strlen(content));
dc34da6e 1597
db628072
RB
1598 p_close(fd);
1599 }
1600 else if (errno != EEXIST)
1601 error = fd;
dc34da6e 1602
662880ca
RB
1603#ifdef GIT_WIN32
1604 if (!error && hidden) {
bdec3363 1605 if (git_win32__set_hidden(path.ptr, true) < 0)
662880ca
RB
1606 error = -1;
1607 }
1608#else
1609 GIT_UNUSED(hidden);
1610#endif
1611
dc34da6e 1612 git_buf_free(&path);
db628072
RB
1613
1614 if (error)
1615 giterr_set(GITERR_OS,
909d5494 1616 "failed to initialize repository with template '%s'", file);
db628072
RB
1617
1618 return error;
dc34da6e
RB
1619}
1620
662880ca 1621static int repo_write_gitlink(
bc737620 1622 const char *in_dir, const char *to_repo, bool use_relative_path)
4b8e27c8 1623{
662880ca
RB
1624 int error;
1625 git_buf buf = GIT_BUF_INIT;
bc737620 1626 git_buf path_to_repo = GIT_BUF_INIT;
662880ca
RB
1627 struct stat st;
1628
1629 git_path_dirname_r(&buf, to_repo);
1630 git_path_to_dir(&buf);
1631 if (git_buf_oom(&buf))
cb8a7961 1632 return -1;
a67a096a 1633
662880ca
RB
1634 /* don't write gitlink to natural workdir */
1635 if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 &&
1636 strcmp(in_dir, buf.ptr) == 0)
1637 {
1638 error = GIT_PASSTHROUGH;
1639 goto cleanup;
1640 }
1641
1642 if ((error = git_buf_joinpath(&buf, in_dir, DOT_GIT)) < 0)
1643 goto cleanup;
1644
1645 if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) {
1646 giterr_set(GITERR_REPOSITORY,
909d5494 1647 "cannot overwrite gitlink file into path '%s'", in_dir);
662880ca
RB
1648 error = GIT_EEXISTS;
1649 goto cleanup;
1650 }
1651
1652 git_buf_clear(&buf);
1653
bc737620
JM
1654 error = git_buf_sets(&path_to_repo, to_repo);
1655
1656 if (!error && use_relative_path)
1657 error = git_path_make_relative(&path_to_repo, in_dir);
1658
1659 if (!error)
1660 error = git_buf_join(&buf, ' ', GIT_FILE_CONTENT_PREFIX, path_to_repo.ptr);
662880ca
RB
1661
1662 if (!error)
18f08264 1663 error = repo_write_template(in_dir, true, DOT_GIT, 0666, true, buf.ptr);
662880ca
RB
1664
1665cleanup:
1666 git_buf_free(&buf);
bc737620 1667 git_buf_free(&path_to_repo);
662880ca
RB
1668 return error;
1669}
1670
ca1b6e54
RB
1671static mode_t pick_dir_mode(git_repository_init_options *opts)
1672{
1673 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_UMASK)
18f08264 1674 return 0777;
ca1b6e54
RB
1675 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_GROUP)
1676 return (0775 | S_ISGID);
1677 if (opts->mode == GIT_REPOSITORY_INIT_SHARED_ALL)
1678 return (0777 | S_ISGID);
1679 return opts->mode;
1680}
1681
662880ca
RB
1682#include "repo_template.h"
1683
1684static int repo_init_structure(
1685 const char *repo_dir,
1686 const char *work_dir,
1687 git_repository_init_options *opts)
1688{
ca1b6e54 1689 int error = 0;
662880ca 1690 repo_template_item *tpl;
ca1b6e54
RB
1691 bool external_tpl =
1692 ((opts->flags & GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) != 0);
1693 mode_t dmode = pick_dir_mode(opts);
bafaf790 1694 bool chmod = opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK;
662880ca
RB
1695
1696 /* Hide the ".git" directory */
17837602 1697#ifdef GIT_WIN32
2eb4edf5 1698 if ((opts->flags & GIT_REPOSITORY_INIT__HAS_DOTGIT) != 0) {
bdec3363 1699 if (git_win32__set_hidden(repo_dir, true) < 0) {
c2c81615 1700 giterr_set(GITERR_OS,
909d5494 1701 "failed to mark Git repository folder as hidden");
cb8a7961
VM
1702 return -1;
1703 }
17837602 1704 }
2eb4edf5
RB
1705#endif
1706
1707 /* Create the .git gitlink if appropriate */
1708 if ((opts->flags & GIT_REPOSITORY_INIT_BARE) == 0 &&
1709 (opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD) == 0)
1710 {
bc737620 1711 if (repo_write_gitlink(work_dir, repo_dir, opts->flags & GIT_REPOSITORY_INIT_RELATIVE_GITLINK) < 0)
cb8a7961 1712 return -1;
97769280 1713 }
1c2c7c0d 1714
ca1b6e54
RB
1715 /* Copy external template if requested */
1716 if (external_tpl) {
0cd1c3bb
L
1717 git_config *cfg = NULL;
1718 const char *tdir = NULL;
1719 bool default_template = false;
a025907e
L
1720 git_buf template_buf = GIT_BUF_INIT;
1721
ca1b6e54
RB
1722 if (opts->template_path)
1723 tdir = opts->template_path;
0cd1c3bb 1724 else if ((error = git_config_open_default(&cfg)) >= 0) {
cc36f424
CMN
1725 if (!git_config_get_path(&template_buf, cfg, "init.templatedir"))
1726 tdir = template_buf.ptr;
ca1b6e54 1727 giterr_clear();
0cd1c3bb
L
1728 }
1729
1730 if (!tdir) {
83634d38 1731 if (!(error = git_sysdir_find_template_dir(&template_buf)))
417472e3 1732 tdir = template_buf.ptr;
0cd1c3bb 1733 default_template = true;
662880ca 1734 }
ca1b6e54 1735
bafaf790 1736 if (tdir) {
62602547
ET
1737 uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS |
1738 GIT_CPDIR_SIMPLE_TO_MODE |
1739 GIT_CPDIR_COPY_DOTFILES;
517341c5
EL
1740 if (opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK)
1741 cpflags |= GIT_CPDIR_CHMOD_DIRS;
1742 error = git_futils_cp_r(tdir, repo_dir, cpflags, dmode);
bafaf790 1743 }
ca1b6e54 1744
0cd1c3bb
L
1745 git_buf_free(&template_buf);
1746 git_config_free(cfg);
1ca3e49f 1747
ca1b6e54 1748 if (error < 0) {
0cd1c3bb 1749 if (!default_template)
ca1b6e54
RB
1750 return error;
1751
1752 /* if template was default, ignore error and use internal */
1753 giterr_clear();
1754 external_tpl = false;
b7b1acfd 1755 error = 0;
ca1b6e54
RB
1756 }
1757 }
1758
1759 /* Copy internal template
1760 * - always ensure existence of dirs
1761 * - only create files if no external template was specified
1762 */
1763 for (tpl = repo_template; !error && tpl->path; ++tpl) {
bafaf790 1764 if (!tpl->content) {
517341c5
EL
1765 uint32_t mkdir_flags = GIT_MKDIR_PATH;
1766 if (chmod)
1767 mkdir_flags |= GIT_MKDIR_CHMOD;
1768
ac2fba0e
ET
1769 error = git_futils_mkdir_relative(
1770 tpl->path, repo_dir, dmode, mkdir_flags, NULL);
bafaf790 1771 }
ca1b6e54 1772 else if (!external_tpl) {
662880ca
RB
1773 const char *content = tpl->content;
1774
1775 if (opts->description && strcmp(tpl->path, GIT_DESC_FILE) == 0)
1776 content = opts->description;
1777
ca1b6e54
RB
1778 error = repo_write_template(
1779 repo_dir, false, tpl->path, tpl->mode, false, content);
662880ca 1780 }
dc34da6e
RB
1781 }
1782
ca1b6e54 1783 return error;
4b8e27c8 1784}
1785
3c42e4ef
RB
1786static int mkdir_parent(git_buf *buf, uint32_t mode, bool skip2)
1787{
0d1b094b
RB
1788 /* When making parent directories during repository initialization
1789 * don't try to set gid or grant world write access
1790 */
3c42e4ef 1791 return git_futils_mkdir(
ac2fba0e 1792 buf->ptr, mode & ~(S_ISGID | 0002),
3c42e4ef
RB
1793 GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR |
1794 (skip2 ? GIT_MKDIR_SKIP_LAST2 : GIT_MKDIR_SKIP_LAST));
1795}
1796
662880ca
RB
1797static int repo_init_directories(
1798 git_buf *repo_path,
1799 git_buf *wd_path,
1800 const char *given_repo,
1801 git_repository_init_options *opts)
4b8e27c8 1802{
662880ca 1803 int error = 0;
3c42e4ef 1804 bool is_bare, add_dotgit, has_dotgit, natural_wd;
ca1b6e54 1805 mode_t dirmode;
932d1baf 1806
3c42e4ef
RB
1807 /* There are three possible rules for what we are allowed to create:
1808 * - MKPATH means anything we need
1809 * - MKDIR means just the .git directory and its parent and the workdir
1810 * - Neither means only the .git directory can be created
1811 *
1812 * There are 5 "segments" of path that we might need to deal with:
1813 * 1. The .git directory
1814 * 2. The parent of the .git directory
1815 * 3. Everything above the parent of the .git directory
1816 * 4. The working directory (often the same as #2)
1817 * 5. Everything above the working directory (often the same as #3)
1818 *
1819 * For all directories created, we start with the init_mode value for
1820 * permissions and then strip off bits in some cases:
1821 *
1822 * For MKPATH, we create #3 (and #5) paths without S_ISGID or S_IWOTH
1823 * For MKPATH and MKDIR, we create #2 (and #4) without S_ISGID
1824 * For all rules, we create #1 using the untouched init_mode
1825 */
1826
662880ca 1827 /* set up repo path */
4b8e27c8 1828
3c42e4ef
RB
1829 is_bare = ((opts->flags & GIT_REPOSITORY_INIT_BARE) != 0);
1830
662880ca
RB
1831 add_dotgit =
1832 (opts->flags & GIT_REPOSITORY_INIT_NO_DOTGIT_DIR) == 0 &&
3c42e4ef 1833 !is_bare &&
662880ca
RB
1834 git__suffixcmp(given_repo, "/" DOT_GIT) != 0 &&
1835 git__suffixcmp(given_repo, "/" GIT_DIR) != 0;
4b8e27c8 1836
662880ca
RB
1837 if (git_buf_joinpath(repo_path, given_repo, add_dotgit ? GIT_DIR : "") < 0)
1838 return -1;
693b23c0 1839
662880ca
RB
1840 has_dotgit = (git__suffixcmp(repo_path->ptr, "/" GIT_DIR) == 0);
1841 if (has_dotgit)
1842 opts->flags |= GIT_REPOSITORY_INIT__HAS_DOTGIT;
1843
1844 /* set up workdir path */
1845
3c42e4ef 1846 if (!is_bare) {
662880ca 1847 if (opts->workdir_path) {
ca1b6e54
RB
1848 if (git_path_join_unrooted(
1849 wd_path, opts->workdir_path, repo_path->ptr, NULL) < 0)
1850 return -1;
662880ca
RB
1851 } else if (has_dotgit) {
1852 if (git_path_dirname_r(wd_path, repo_path->ptr) < 0)
1853 return -1;
1854 } else {
909d5494 1855 giterr_set(GITERR_REPOSITORY, "cannot pick working directory"
662880ca
RB
1856 " for non-bare repository that isn't a '.git' directory");
1857 return -1;
1858 }
693b23c0 1859
662880ca
RB
1860 if (git_path_to_dir(wd_path) < 0)
1861 return -1;
1862 } else {
1863 git_buf_clear(wd_path);
1864 }
1865
1866 natural_wd =
1867 has_dotgit &&
1868 wd_path->size > 0 &&
1869 wd_path->size + strlen(GIT_DIR) == repo_path->size &&
1870 memcmp(repo_path->ptr, wd_path->ptr, wd_path->size) == 0;
1871 if (natural_wd)
1872 opts->flags |= GIT_REPOSITORY_INIT__NATURAL_WD;
1873
662880ca
RB
1874 /* create directories as needed / requested */
1875
ca1b6e54 1876 dirmode = pick_dir_mode(opts);
662880ca 1877
3c42e4ef
RB
1878 if ((opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) {
1879 /* create path #5 */
1880 if (wd_path->size > 0 &&
1881 (error = mkdir_parent(wd_path, dirmode, false)) < 0)
1882 return error;
1883
1884 /* create path #3 (if not the same as #5) */
1885 if (!natural_wd &&
1886 (error = mkdir_parent(repo_path, dirmode, has_dotgit)) < 0)
1887 return error;
1888 }
1889
1890 if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 ||
1891 (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0)
1892 {
1893 /* create path #4 */
1894 if (wd_path->size > 0 &&
1895 (error = git_futils_mkdir(
ac2fba0e 1896 wd_path->ptr, dirmode & ~S_ISGID,
3c42e4ef
RB
1897 GIT_MKDIR_VERIFY_DIR)) < 0)
1898 return error;
1899
1900 /* create path #2 (if not the same as #4) */
1901 if (!natural_wd &&
1902 (error = git_futils_mkdir(
ac2fba0e 1903 repo_path->ptr, dirmode & ~S_ISGID,
3c42e4ef
RB
1904 GIT_MKDIR_VERIFY_DIR | GIT_MKDIR_SKIP_LAST)) < 0)
1905 return error;
662880ca 1906 }
662880ca 1907
ca1b6e54
RB
1908 if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 ||
1909 (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0 ||
1910 has_dotgit)
1911 {
3c42e4ef 1912 /* create path #1 */
ac2fba0e 1913 error = git_futils_mkdir(repo_path->ptr, dirmode,
18f08264 1914 GIT_MKDIR_VERIFY_DIR | ((dirmode & S_ISGID) ? GIT_MKDIR_CHMOD : 0));
662880ca 1915 }
ca1b6e54 1916
662880ca
RB
1917 /* prettify both directories now that they are created */
1918
1919 if (!error) {
1920 error = git_path_prettify_dir(repo_path, repo_path->ptr, NULL);
1921
1922 if (!error && wd_path->size > 0)
1923 error = git_path_prettify_dir(wd_path, wd_path->ptr, NULL);
1924 }
1925
1926 return error;
1927}
1928
1929static int repo_init_create_origin(git_repository *repo, const char *url)
1930{
1931 int error;
1932 git_remote *remote;
1933
29f27599 1934 if (!(error = git_remote_create(&remote, repo, GIT_REMOTE_ORIGIN, url))) {
662880ca
RB
1935 git_remote_free(remote);
1936 }
1937
1938 return error;
1939}
1940
1941int git_repository_init(
1942 git_repository **repo_out, const char *path, unsigned is_bare)
1943{
b4d13652 1944 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
662880ca 1945
662880ca
RB
1946 opts.flags = GIT_REPOSITORY_INIT_MKPATH; /* don't love this default */
1947 if (is_bare)
1948 opts.flags |= GIT_REPOSITORY_INIT_BARE;
1949
1950 return git_repository_init_ext(repo_out, path, &opts);
1951}
1952
1953int git_repository_init_ext(
c9fc4a6f 1954 git_repository **out,
662880ca
RB
1955 const char *given_repo,
1956 git_repository_init_options *opts)
1957{
1958 int error;
c09fd54e
PS
1959 git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT,
1960 common_path = GIT_BUF_INIT;
466d2e7a 1961 const char *wd;
662880ca 1962
c9fc4a6f 1963 assert(out && given_repo && opts);
662880ca 1964
c7231c45 1965 GITERR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options");
b4d13652 1966
662880ca
RB
1967 error = repo_init_directories(&repo_path, &wd_path, given_repo, opts);
1968 if (error < 0)
693b23c0 1969 goto cleanup;
662880ca 1970
466d2e7a 1971 wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_buf_cstr(&wd_path);
c09fd54e 1972 if (valid_repository_path(&repo_path, &common_path)) {
662880ca
RB
1973
1974 if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) {
1975 giterr_set(GITERR_REPOSITORY,
909d5494 1976 "attempt to reinitialize '%s'", given_repo);
662880ca
RB
1977 error = GIT_EEXISTS;
1978 goto cleanup;
1979 }
1980
1981 opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT;
1982
ca1b6e54 1983 error = repo_init_config(
466d2e7a 1984 repo_path.ptr, wd, opts->flags, opts->mode);
662880ca
RB
1985
1986 /* TODO: reinitialize the templates */
1987 }
1988 else {
1989 if (!(error = repo_init_structure(
466d2e7a 1990 repo_path.ptr, wd, opts)) &&
ca1b6e54 1991 !(error = repo_init_config(
466d2e7a 1992 repo_path.ptr, wd, opts->flags, opts->mode)))
854b5c70 1993 error = git_repository_create_head(
5173ea92 1994 repo_path.ptr, opts->initial_head);
cb8a7961 1995 }
662880ca
RB
1996 if (error < 0)
1997 goto cleanup;
1998
5173ea92 1999 error = git_repository_open(out, repo_path.ptr);
d2d6912e 2000
662880ca 2001 if (!error && opts->origin_url)
c9fc4a6f 2002 error = repo_init_create_origin(*out, opts->origin_url);
693b23c0 2003
2004cleanup:
c09fd54e 2005 git_buf_free(&common_path);
662880ca
RB
2006 git_buf_free(&repo_path);
2007 git_buf_free(&wd_path);
2008
2009 return error;
40c44d2f 2010}
35502d2e 2011
c682886e 2012int git_repository_head_detached(git_repository *repo)
35502d2e
CMN
2013{
2014 git_reference *ref;
9462c471 2015 git_odb *odb = NULL;
cb8a7961 2016 int exists;
9462c471 2017
cb8a7961
VM
2018 if (git_repository_odb__weakptr(&odb, repo) < 0)
2019 return -1;
35502d2e 2020
cb8a7961
VM
2021 if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0)
2022 return -1;
35502d2e 2023
75abd2b9
MS
2024 if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
2025 git_reference_free(ref);
35502d2e 2026 return 0;
75abd2b9 2027 }
35502d2e 2028
2508cc66 2029 exists = git_odb_exists(odb, git_reference_target(ref));
75abd2b9
MS
2030
2031 git_reference_free(ref);
cb8a7961 2032 return exists;
35502d2e
CMN
2033}
2034
04fb12ab
PS
2035static int read_worktree_head(git_buf *out, git_repository *repo, const char *name)
2036{
2037 git_buf path = GIT_BUF_INIT;
2038 int err;
2039
2040 assert(out && repo && name);
2041
2042 git_buf_clear(out);
2043
2044 if ((err = git_buf_printf(&path, "%s/worktrees/%s/HEAD", repo->commondir, name)) < 0)
2045 goto out;
2046 if (!git_path_exists(path.ptr))
2047 {
2048 err = -1;
2049 goto out;
2050 }
2051
2052 if ((err = git_futils_readbuffer(out, path.ptr)) < 0)
2053 goto out;
2054 git_buf_rtrim(out);
2055
2056out:
2057 git_buf_free(&path);
2058
2059 return err;
2060}
2061
2062int git_repository_head_detached_for_worktree(git_repository *repo, const char *name)
2063{
2064 git_buf buf = GIT_BUF_INIT;
2065 int ret;
2066
2067 assert(repo && name);
2068
2069 if (read_worktree_head(&buf, repo, name) < 0)
2070 return -1;
2071
2072 ret = git__strncmp(buf.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) != 0;
2073 git_buf_free(&buf);
2074
2075 return ret;
2076}
2077
3601c4bf 2078int git_repository_head(git_reference **head_out, git_repository *repo)
35502d2e 2079{
b1a3a70e 2080 git_reference *head;
8b05bea8 2081 int error;
2082
b1a3a70e 2083 if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
2084 return error;
2085
2086 if (git_reference_type(head) == GIT_REF_OID) {
2087 *head_out = head;
2088 return 0;
2089 }
2090
2508cc66 2091 error = git_reference_lookup_resolved(head_out, repo, git_reference_symbolic_target(head), -1);
b1a3a70e 2092 git_reference_free(head);
8b05bea8 2093
605da51a 2094 return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error;
3601c4bf 2095}
2096
04fb12ab
PS
2097int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name)
2098{
2099 git_buf buf = GIT_BUF_INIT;
2100 git_reference *head;
2101 int err;
2102
2103 assert(out && repo && name);
2104
2105 *out = NULL;
2106
2107 if (git_repository_head_detached_for_worktree(repo, name))
2108 return -1;
2109 if ((err = read_worktree_head(&buf, repo, name)) < 0)
2110 goto out;
2111
2112 /* We can only resolve symbolic references */
2113 if (git__strncmp(buf.ptr, GIT_SYMREF, strlen(GIT_SYMREF)))
2114 {
2115 err = -1;
2116 goto out;
2117 }
2118 git_buf_consume(&buf, buf.ptr + strlen(GIT_SYMREF));
2119
2120 if ((err = git_reference_lookup(&head, repo, buf.ptr)) < 0)
2121 goto out;
2122 if (git_reference_type(head) == GIT_REF_OID)
2123 {
2124 *out = head;
2125 err = 0;
2126 goto out;
2127 }
2128
2129 err = git_reference_lookup_resolved(
2130 out, repo, git_reference_symbolic_target(head), -1);
2131 git_reference_free(head);
2132
2133out:
2134 git_buf_free(&buf);
2135
2136 return err;
2137}
2138
605da51a 2139int git_repository_head_unborn(git_repository *repo)
3601c4bf 2140{
cb8a7961 2141 git_reference *ref = NULL;
3601c4bf 2142 int error;
2143
2144 error = git_repository_head(&ref, repo);
cb8a7961 2145 git_reference_free(ref);
35502d2e 2146
7c9bf891
ET
2147 if (error == GIT_EUNBORNBRANCH) {
2148 giterr_clear();
cb8a7961 2149 return 1;
7c9bf891 2150 }
75abd2b9 2151
cb8a7961
VM
2152 if (error < 0)
2153 return -1;
2154
2155 return 0;
35502d2e 2156}
e0011be3 2157
0066955d 2158static int at_least_one_cb(const char *refname, void *payload)
41233c40 2159{
6091457e 2160 GIT_UNUSED(refname);
2161 GIT_UNUSED(payload);
25e0b157 2162 return GIT_PASSTHROUGH;
6091457e 2163}
41233c40 2164
6091457e 2165static int repo_contains_no_reference(git_repository *repo)
2166{
ec24e542 2167 int error = git_reference_foreach_name(repo, &at_least_one_cb, NULL);
0f489fb2 2168
25e0b157 2169 if (error == GIT_PASSTHROUGH)
0f489fb2 2170 return 0;
ec24e542 2171
e976b56d
RB
2172 if (!error)
2173 return 1;
ec24e542 2174
e976b56d 2175 return error;
6091457e 2176}
75abd2b9 2177
6091457e 2178int git_repository_is_empty(git_repository *repo)
2179{
2180 git_reference *head = NULL;
42181836 2181 int is_empty = 0;
cb8a7961 2182
6091457e 2183 if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0)
cb8a7961
VM
2184 return -1;
2185
42181836
RB
2186 if (git_reference_type(head) == GIT_REF_SYMBOLIC)
2187 is_empty =
2188 (strcmp(git_reference_symbolic_target(head),
2189 GIT_REFS_HEADS_DIR "master") == 0) &&
2190 repo_contains_no_reference(repo);
6091457e 2191
6091457e 2192 git_reference_free(head);
42181836
RB
2193
2194 return is_empty;
41233c40
VM
2195}
2196
cb3269c9
PS
2197int git_repository_item_path(git_buf *out, git_repository *repo, git_repository_item_t item)
2198{
2199 const char *parent;
2200
2201 switch (items[item].parent) {
2202 case GIT_REPOSITORY_ITEM_GITDIR:
2203 parent = git_repository_path(repo);
2204 break;
2205 case GIT_REPOSITORY_ITEM_WORKDIR:
2206 parent = git_repository_workdir(repo);
2207 break;
2208 case GIT_REPOSITORY_ITEM_COMMONDIR:
2209 parent = git_repository_commondir(repo);
2210 break;
2211 default:
2212 giterr_set(GITERR_INVALID, "Invalid item directory");
2213 return -1;
2214 }
2215
2216 if (parent == NULL) {
2217 giterr_set(GITERR_INVALID, "Path cannot exist in repository");
2218 return -1;
2219 }
2220
2221 if (git_buf_sets(out, parent) < 0)
2222 return -1;
2223
2224 if (items[item].name) {
2225 if (git_buf_joinpath(out, parent, items[item].name) < 0)
2226 return -1;
2227 }
2228
2229 if (items[item].directory) {
2230 if (git_path_to_dir(out) < 0)
2231 return -1;
2232 }
2233
2234 return 0;
2235}
2236
9462c471 2237const char *git_repository_path(git_repository *repo)
4a34b3a9 2238{
2239 assert(repo);
9462c471
VM
2240 return repo->path_repository;
2241}
4a34b3a9 2242
9462c471
VM
2243const char *git_repository_workdir(git_repository *repo)
2244{
2245 assert(repo);
602ee38b 2246
9462c471
VM
2247 if (repo->is_bare)
2248 return NULL;
602ee38b 2249
9462c471
VM
2250 return repo->workdir;
2251}
602ee38b 2252
c09fd54e
PS
2253const char *git_repository_commondir(git_repository *repo)
2254{
2255 assert(repo);
2256 return repo->commondir;
2257}
2258
991a56c7
RB
2259int git_repository_set_workdir(
2260 git_repository *repo, const char *workdir, int update_gitlink)
9462c471 2261{
991a56c7 2262 int error = 0;
b78fb64d 2263 git_buf path = GIT_BUF_INIT;
2264
9462c471 2265 assert(repo && workdir);
602ee38b 2266
b78fb64d 2267 if (git_path_prettify_dir(&path, workdir, NULL) < 0)
2268 return -1;
9462c471 2269
991a56c7
RB
2270 if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0)
2271 return 0;
9462c471 2272
991a56c7
RB
2273 if (update_gitlink) {
2274 git_config *config;
2275
2276 if (git_repository_config__weakptr(&config, repo) < 0)
2277 return -1;
2278
bc737620 2279 error = repo_write_gitlink(path.ptr, git_repository_path(repo), false);
991a56c7
RB
2280
2281 /* passthrough error means gitlink is unnecessary */
2282 if (error == GIT_PASSTHROUGH)
54b2a37a 2283 error = git_config_delete_entry(config, "core.worktree");
991a56c7
RB
2284 else if (!error)
2285 error = git_config_set_string(config, "core.worktree", path.ptr);
2286
2287 if (!error)
2288 error = git_config_set_bool(config, "core.bare", false);
2289 }
2290
2291 if (!error) {
2292 char *old_workdir = repo->workdir;
2293
2294 repo->workdir = git_buf_detach(&path);
2295 repo->is_bare = 0;
2296
2297 git__free(old_workdir);
2298 }
2299
2300 return error;
4a34b3a9 2301}
fa9bcd81 2302
2303int git_repository_is_bare(git_repository *repo)
2304{
2305 assert(repo);
2306 return repo->is_bare;
2307}
f917481e 2308
79ab3ef6
PS
2309int git_repository_is_worktree(git_repository *repo)
2310{
2311 assert(repo);
2312 return repo->is_worktree;
2313}
2314
1fbeb2f0
RB
2315int git_repository_set_bare(git_repository *repo)
2316{
2317 int error;
2318 git_config *config;
2319
2320 assert(repo);
2321
2322 if (repo->is_bare)
2323 return 0;
2324
74240afb
T
2325 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
2326 return error;
2327
b2a7bcdb 2328 if ((error = git_config_set_bool(config, "core.bare", true)) < 0)
74240afb 2329 return error;
1fbeb2f0 2330
74240afb
T
2331 if ((error = git_config__update_entry(config, "core.worktree", NULL, true, true)) < 0)
2332 return error;
1fbeb2f0
RB
2333
2334 git__free(repo->workdir);
2335 repo->workdir = NULL;
1fbeb2f0
RB
2336 repo->is_bare = 1;
2337
74240afb 2338 return 0;
1fbeb2f0
RB
2339}
2340
f917481e
RB
2341int git_repository_head_tree(git_tree **tree, git_repository *repo)
2342{
5cec896a 2343 git_reference *head;
2344 git_object *obj;
2345 int error;
f917481e 2346
5cec896a 2347 if ((error = git_repository_head(&head, repo)) < 0)
2348 return error;
f917481e 2349
5cec896a 2350 if ((error = git_reference_peel(&obj, head, GIT_OBJ_TREE)) < 0)
2351 goto cleanup;
f917481e
RB
2352
2353 *tree = (git_tree *)obj;
5cec896a 2354
2355cleanup:
2356 git_reference_free(head);
2357 return error;
f917481e 2358}
074841ec 2359
867a36f3
ET
2360int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head)
2361{
2362 git_filebuf file = GIT_FILEBUF_INIT;
2363 git_buf file_path = GIT_BUF_INIT;
2364 char orig_head_str[GIT_OID_HEXSZ];
2365 int error = 0;
2366
2367 git_oid_fmt(orig_head_str, orig_head);
2368
2369 if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 &&
2370 (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 &&
2371 (error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0)
2372 error = git_filebuf_commit(&file);
2373
2374 if (error < 0)
2375 git_filebuf_cleanup(&file);
2376
2377 git_buf_free(&file_path);
2378
2379 return error;
2380}
2381
3158e2fe 2382int git_repository_message(git_buf *out, git_repository *repo)
074841ec 2383{
7a3bd1e7 2384 git_buf path = GIT_BUF_INIT;
0ac349a9 2385 struct stat st;
0ac349a9 2386 int error;
074841ec 2387
7a3bd1e7 2388 git_buf_sanitize(out);
3d1c9f61 2389
632d8b23 2390 if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
0ac349a9 2391 return -1;
074841ec 2392
e9ca852e 2393 if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) {
074841ec
CMN
2394 if (errno == ENOENT)
2395 error = GIT_ENOTFOUND;
909d5494 2396 giterr_set(GITERR_OS, "could not access message file");
3158e2fe
RB
2397 } else {
2398 error = git_futils_readbuffer(out, git_buf_cstr(&path));
0ac349a9 2399 }
074841ec 2400
7a3bd1e7 2401 git_buf_free(&path);
e9ca852e
RB
2402
2403 return error;
074841ec
CMN
2404}
2405
2406int git_repository_message_remove(git_repository *repo)
2407{
0ac349a9
VM
2408 git_buf path = GIT_BUF_INIT;
2409 int error;
074841ec 2410
632d8b23 2411 if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
0ac349a9 2412 return -1;
074841ec
CMN
2413
2414 error = p_unlink(git_buf_cstr(&path));
2415 git_buf_free(&path);
2416
2417 return error;
2418}
47bfa0be
RB
2419
2420int git_repository_hashfile(
0cb16fe9
L
2421 git_oid *out,
2422 git_repository *repo,
2423 const char *path,
2424 git_otype type,
2425 const char *as_path)
47bfa0be
RB
2426{
2427 int error;
85d54812 2428 git_filter_list *fl = NULL;
b1127a30 2429 git_file fd = -1;
47bfa0be
RB
2430 git_off_t len;
2431 git_buf full_path = GIT_BUF_INIT;
2432
a13fb55a
RB
2433 assert(out && path && repo); /* as_path can be NULL */
2434
2435 /* At some point, it would be nice if repo could be NULL to just
2436 * apply filter rules defined in system and global files, but for
2437 * now that is not possible because git_filters_load() needs it.
2438 */
47bfa0be
RB
2439
2440 error = git_path_join_unrooted(
526182d2 2441 &full_path, path, git_repository_workdir(repo), NULL);
47bfa0be
RB
2442 if (error < 0)
2443 return error;
2444
2445 if (!as_path)
2446 as_path = path;
2447
2448 /* passing empty string for "as_path" indicated --no-filters */
2449 if (strlen(as_path) > 0) {
4b11f25a 2450 error = git_filter_list_load(
5269008c 2451 &fl, repo, NULL, as_path,
795eaccd 2452 GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT);
47bfa0be
RB
2453 if (error < 0)
2454 return error;
2455 } else {
2456 error = 0;
2457 }
2458
2459 /* at this point, error is a count of the number of loaded filters */
2460
2461 fd = git_futils_open_ro(full_path.ptr);
2462 if (fd < 0) {
2463 error = fd;
2464 goto cleanup;
2465 }
2466
2467 len = git_futils_filesize(fd);
2468 if (len < 0) {
75050223 2469 error = (int)len;
47bfa0be
RB
2470 goto cleanup;
2471 }
2472
2473 if (!git__is_sizet(len)) {
909d5494 2474 giterr_set(GITERR_OS, "file size overflow for 32-bit systems");
47bfa0be
RB
2475 error = -1;
2476 goto cleanup;
2477 }
2478
85d54812 2479 error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, fl);
47bfa0be
RB
2480
2481cleanup:
b1127a30
SS
2482 if (fd >= 0)
2483 p_close(fd);
85d54812 2484 git_filter_list_free(fl);
47bfa0be
RB
2485 git_buf_free(&full_path);
2486
2487 return error;
2488}
2489
4e498646 2490static int checkout_message(git_buf *out, git_reference *old, const char *new)
44af67a8 2491{
4e498646
CMN
2492 git_buf_puts(out, "checkout: moving from ");
2493
2494 if (git_reference_type(old) == GIT_REF_SYMBOLIC)
2495 git_buf_puts(out, git_reference__shorthand(git_reference_symbolic_target(old)));
2496 else
2497 git_buf_puts(out, git_oid_tostr_s(git_reference_target(old)));
2498
2499 git_buf_puts(out, " to ");
2500
2501 if (git_reference__is_branch(new))
2502 git_buf_puts(out, git_reference__shorthand(new));
2503 else
2504 git_buf_puts(out, new);
2505
2506 if (git_buf_oom(out))
2507 return -1;
2508
2509 return 0;
44af67a8 2510}
2511
2512int git_repository_set_head(
2513 git_repository* repo,
4e498646 2514 const char* refname)
44af67a8 2515{
4e498646
CMN
2516 git_reference *ref = NULL, *current = NULL, *new_head = NULL;
2517 git_buf log_message = GIT_BUF_INIT;
44af67a8 2518 int error;
2519
2520 assert(repo && refname);
2521
4e498646
CMN
2522 if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
2523 return error;
2524
2525 if ((error = checkout_message(&log_message, current, refname)) < 0)
2526 goto cleanup;
2527
44af67a8 2528 error = git_reference_lookup(&ref, repo, refname);
2529 if (error < 0 && error != GIT_ENOTFOUND)
4e498646 2530 goto cleanup;
44af67a8 2531
2532 if (!error) {
94f263f5
BS
2533 if (git_reference_is_branch(ref)) {
2534 error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE,
4e498646 2535 git_reference_name(ref), true, git_buf_cstr(&log_message));
94f263f5 2536 } else {
4e498646 2537 error = git_repository_set_head_detached(repo, git_reference_target(ref));
94f263f5 2538 }
4e498646 2539 } else if (git_reference__is_branch(refname)) {
94f263f5 2540 error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname,
4e498646 2541 true, git_buf_cstr(&log_message));
94f263f5 2542 }
44af67a8 2543
4e498646 2544cleanup:
fe21d708 2545 git_buf_free(&log_message);
4e498646 2546 git_reference_free(current);
44af67a8 2547 git_reference_free(ref);
2548 git_reference_free(new_head);
2549 return error;
2550}
2551
62d38a1d 2552static int detach(git_repository *repo, const git_oid *id, const char *from)
4ebe38bd 2553{
2554 int error;
4e498646
CMN
2555 git_buf log_message = GIT_BUF_INIT;
2556 git_object *object = NULL, *peeled = NULL;
2557 git_reference *new_head = NULL, *current = NULL;
4ebe38bd 2558
62d38a1d 2559 assert(repo && id);
4ebe38bd 2560
4e498646 2561 if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
4ebe38bd 2562 return error;
2563
62d38a1d 2564 if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0)
4e498646
CMN
2565 goto cleanup;
2566
4ebe38bd 2567 if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0)
2568 goto cleanup;
2569
62d38a1d
CMN
2570 if (from == NULL)
2571 from = git_oid_tostr_s(git_object_id(peeled));
2572
2573 if ((error = checkout_message(&log_message, current, from)) < 0)
4e498646
CMN
2574 goto cleanup;
2575
2576 error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message));
4ebe38bd 2577
2578cleanup:
fe21d708 2579 git_buf_free(&log_message);
4ebe38bd 2580 git_object_free(object);
2581 git_object_free(peeled);
4e498646 2582 git_reference_free(current);
4ebe38bd 2583 git_reference_free(new_head);
2584 return error;
2585}
2586
62d38a1d
CMN
2587int git_repository_set_head_detached(
2588 git_repository* repo,
2589 const git_oid* commitish)
2590{
2591 return detach(repo, commitish, NULL);
2592}
2593
2594int git_repository_set_head_detached_from_annotated(
2595 git_repository *repo,
2596 const git_annotated_commit *commitish)
2597{
2598 assert(repo && commitish);
2599
d5592378 2600 return detach(repo, git_annotated_commit_id(commitish), commitish->description);
62d38a1d
CMN
2601}
2602
4e498646 2603int git_repository_detach_head(git_repository* repo)
3f4c3072 2604{
4e498646 2605 git_reference *old_head = NULL, *new_head = NULL, *current = NULL;
3f4c3072 2606 git_object *object = NULL;
4e498646 2607 git_buf log_message = GIT_BUF_INIT;
8b05bea8 2608 int error;
3f4c3072 2609
2610 assert(repo);
2611
4e498646 2612 if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
8b05bea8 2613 return error;
3f4c3072 2614
4e498646
CMN
2615 if ((error = git_repository_head(&old_head, repo)) < 0)
2616 goto cleanup;
2617
2508cc66 2618 if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJ_COMMIT)) < 0)
3f4c3072 2619 goto cleanup;
2620
4e498646
CMN
2621 if ((error = checkout_message(&log_message, current, git_oid_tostr_s(git_object_id(object)))) < 0)
2622 goto cleanup;
2623
010cec3a 2624 error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head),
4e498646 2625 1, git_buf_cstr(&log_message));
3f4c3072 2626
2627cleanup:
fe21d708 2628 git_buf_free(&log_message);
3f4c3072 2629 git_object_free(object);
2630 git_reference_free(old_head);
2631 git_reference_free(new_head);
4e498646 2632 git_reference_free(current);
3f4c3072 2633 return error;
2634}
632d8b23 2635
31966d20 2636/**
2637 * Loosely ported from git.git
2638 * https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh#L198-289
2639 */
632d8b23
ET
2640int git_repository_state(git_repository *repo)
2641{
2642 git_buf repo_path = GIT_BUF_INIT;
2643 int state = GIT_REPOSITORY_STATE_NONE;
2644
2645 assert(repo);
2646
2647 if (git_buf_puts(&repo_path, repo->path_repository) < 0)
2648 return -1;
2649
31966d20 2650 if (git_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE))
2651 state = GIT_REPOSITORY_STATE_REBASE_INTERACTIVE;
2652 else if (git_path_contains_dir(&repo_path, GIT_REBASE_MERGE_DIR))
2653 state = GIT_REPOSITORY_STATE_REBASE_MERGE;
2654 else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_REBASING_FILE))
2655 state = GIT_REPOSITORY_STATE_REBASE;
2656 else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_APPLYING_FILE))
2657 state = GIT_REPOSITORY_STATE_APPLY_MAILBOX;
2658 else if (git_path_contains_dir(&repo_path, GIT_REBASE_APPLY_DIR))
2659 state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE;
2660 else if (git_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE))
632d8b23 2661 state = GIT_REPOSITORY_STATE_MERGE;
2ea40fda 2662 else if (git_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE)) {
632d8b23 2663 state = GIT_REPOSITORY_STATE_REVERT;
2ea40fda
CMN
2664 if (git_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) {
2665 state = GIT_REPOSITORY_STATE_REVERT_SEQUENCE;
2666 }
2667 } else if (git_path_contains_file(&repo_path, GIT_CHERRYPICK_HEAD_FILE)) {
0ba4dca5 2668 state = GIT_REPOSITORY_STATE_CHERRYPICK;
2ea40fda
CMN
2669 if (git_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) {
2670 state = GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE;
2671 }
2672 } else if (git_path_contains_file(&repo_path, GIT_BISECT_LOG_FILE))
31966d20 2673 state = GIT_REPOSITORY_STATE_BISECT;
632d8b23
ET
2674
2675 git_buf_free(&repo_path);
2676 return state;
2677}
93d8f77f 2678
c3dcbe84
VM
2679int git_repository__cleanup_files(
2680 git_repository *repo, const char *files[], size_t files_len)
bab0b9f2 2681{
c3dcbe84 2682 git_buf buf = GIT_BUF_INIT;
bab0b9f2 2683 size_t i;
c3dcbe84 2684 int error;
bab0b9f2 2685
c3dcbe84
VM
2686 for (error = 0, i = 0; !error && i < files_len; ++i) {
2687 const char *path;
bab0b9f2 2688
c3dcbe84
VM
2689 if (git_buf_joinpath(&buf, repo->path_repository, files[i]) < 0)
2690 return -1;
bab0b9f2 2691
c3dcbe84
VM
2692 path = git_buf_cstr(&buf);
2693
2694 if (git_path_isfile(path)) {
2695 error = p_unlink(path);
2696 } else if (git_path_isdir(path)) {
2697 error = git_futils_rmdir_r(path, NULL,
2698 GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS);
2699 }
2700
2701 git_buf_clear(&buf);
2702 }
bab0b9f2 2703
c3dcbe84 2704 git_buf_free(&buf);
bab0b9f2
ET
2705 return error;
2706}
2707
2708static const char *state_files[] = {
2709 GIT_MERGE_HEAD_FILE,
2710 GIT_MERGE_MODE_FILE,
2711 GIT_MERGE_MSG_FILE,
2712 GIT_REVERT_HEAD_FILE,
0ba4dca5 2713 GIT_CHERRYPICK_HEAD_FILE,
c0311295
JG
2714 GIT_BISECT_LOG_FILE,
2715 GIT_REBASE_MERGE_DIR,
2716 GIT_REBASE_APPLY_DIR,
2ea40fda 2717 GIT_SEQUENCER_DIR,
bab0b9f2
ET
2718};
2719
2720int git_repository_state_cleanup(git_repository *repo)
2721{
2722 assert(repo);
2723
2724 return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
2725}
2726
93d8f77f
BS
2727int git_repository_is_shallow(git_repository *repo)
2728{
2729 git_buf path = GIT_BUF_INIT;
2730 struct stat st;
6f0b8142 2731 int error;
93d8f77f 2732
3dbd9a0e
JG
2733 if ((error = git_buf_joinpath(&path, repo->path_repository, "shallow")) < 0)
2734 return error;
2735
6f0b8142
BS
2736 error = git_path_lstat(path.ptr, &st);
2737 git_buf_free(&path);
93d8f77f 2738
9bda5fb8
BS
2739 if (error == GIT_ENOTFOUND) {
2740 giterr_clear();
93d8f77f 2741 return 0;
9bda5fb8
BS
2742 }
2743
864535cf
BS
2744 if (error < 0)
2745 return error;
2746 return st.st_size == 0 ? 0 : 1;
93d8f77f 2747}
b9f81997 2748
702efc89
RB
2749int git_repository_init_init_options(
2750 git_repository_init_options *opts, unsigned int version)
b9f81997 2751{
702efc89
RB
2752 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2753 opts, version, git_repository_init_options,
2754 GIT_REPOSITORY_INIT_OPTIONS_INIT);
2755 return 0;
b9f81997 2756}
659cf202
CMN
2757
2758int git_repository_ident(const char **name, const char **email, const git_repository *repo)
2759{
2760 *name = repo->ident_name;
2761 *email = repo->ident_email;
2762
2763 return 0;
2764}
2765
2766int git_repository_set_ident(git_repository *repo, const char *name, const char *email)
2767{
2768 char *tmp_name = NULL, *tmp_email = NULL;
2769
2770 if (name) {
2771 tmp_name = git__strdup(name);
2772 GITERR_CHECK_ALLOC(tmp_name);
2773 }
2774
2775 if (email) {
2776 tmp_email = git__strdup(email);
2777 GITERR_CHECK_ALLOC(tmp_email);
2778 }
2779
2780 tmp_name = git__swap(repo->ident_name, tmp_name);
2781 tmp_email = git__swap(repo->ident_email, tmp_email);
2782
2783 git__free(tmp_name);
2784 git__free(tmp_email);
2785
2786 return 0;
2787}
4d99c4cf
BP
2788
2789int git_repository_submodule_cache_all(git_repository *repo)
2790{
2791 int error;
2792
2793 assert(repo);
2794
2795 if ((error = git_strmap_alloc(&repo->submodule_cache)))
2796 return error;
2797
2798 error = git_submodule__map(repo, repo->submodule_cache);
2799 return error;
2800}
2801
2802int git_repository_submodule_cache_clear(git_repository *repo)
2803{
2804 git_submodule *sm;
2805 assert(repo);
2806 if (repo->submodule_cache == NULL) {
2807 return 0;
2808 }
2809 git_strmap_foreach_value(repo->submodule_cache, sm, {
2810 git_submodule_free(sm);
2811 });
2812 git_strmap_free(repo->submodule_cache);
2813 repo->submodule_cache = 0;
2814 return 0;
2815}