File Coverage

deps/libgit2/src/libgit2/repository.c
Criterion Covered Total %
statement 884 1650 53.5
branch 449 1184 37.9
condition n/a
subroutine n/a
pod n/a
total 1333 2834 47.0


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