File Coverage

deps/libgit2/src/repository.c
Criterion Covered Total %
statement 814 1468 55.4
branch 414 1060 39.0
condition n/a
subroutine n/a
pod n/a
total 1228 2528 48.5


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