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