File Coverage

deps/libgit2/src/repository.c
Criterion Covered Total %
statement 813 1475 55.1
branch 414 1062 38.9
condition n/a
subroutine n/a
pod n/a
total 1227 2537 48.3


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 63           static void set_odb(git_repository *repo, git_odb *odb)
90             {
91 63 100         if (odb) {
92 2           GIT_REFCOUNT_OWN(odb, repo);
93 2           GIT_REFCOUNT_INC(odb);
94             }
95              
96 63 100         if ((odb = git__swap(repo->_odb, odb)) != NULL) {
97 35           GIT_REFCOUNT_OWN(odb, NULL);
98 35           git_odb_free(odb);
99             }
100 63           }
101              
102 61           static void set_refdb(git_repository *repo, git_refdb *refdb)
103             {
104 61 50         if (refdb) {
105 0           GIT_REFCOUNT_OWN(refdb, repo);
106 0           GIT_REFCOUNT_INC(refdb);
107             }
108              
109 61 100         if ((refdb = git__swap(repo->_refdb, refdb)) != NULL) {
110 52           GIT_REFCOUNT_OWN(refdb, NULL);
111 52           git_refdb_free(refdb);
112             }
113 61           }
114              
115 61           static void set_config(git_repository *repo, git_config *config)
116             {
117 61 50         if (config) {
118 0           GIT_REFCOUNT_OWN(config, repo);
119 0           GIT_REFCOUNT_INC(config);
120             }
121              
122 61 50         if ((config = git__swap(repo->_config, config)) != NULL) {
123 61           GIT_REFCOUNT_OWN(config, NULL);
124 61           git_config_free(config);
125             }
126              
127 61           git_repository__configmap_lookup_cache_clear(repo);
128 61           }
129              
130 63           static void set_index(git_repository *repo, git_index *index)
131             {
132 63 100         if (index) {
133 1           GIT_REFCOUNT_OWN(index, repo);
134 1           GIT_REFCOUNT_INC(index);
135             }
136              
137 63 100         if ((index = git__swap(repo->_index, index)) != NULL) {
138 17           GIT_REFCOUNT_OWN(index, NULL);
139 17           git_index_free(index);
140             }
141 63           }
142              
143 61           int git_repository__cleanup(git_repository *repo)
144             {
145 61 50         assert(repo);
146              
147 61           git_repository_submodule_cache_clear(repo);
148 61           git_cache_clear(&repo->objects);
149 61           git_attr_cache_flush(repo);
150              
151 61           set_config(repo, NULL);
152 61           set_index(repo, NULL);
153 61           set_odb(repo, NULL);
154 61           set_refdb(repo, NULL);
155              
156 61           return 0;
157             }
158              
159 79           void git_repository_free(git_repository *repo)
160             {
161             size_t i;
162              
163 79 100         if (repo == NULL)
164 18           return;
165              
166 61           git_repository__cleanup(repo);
167              
168 61           git_cache_dispose(&repo->objects);
169              
170 61           git_diff_driver_registry_free(repo->diff_drivers);
171 61           repo->diff_drivers = NULL;
172              
173 61 50         for (i = 0; i < repo->reserved_names.size; i++)
174 0 0         git_buf_dispose(git_array_get(repo->reserved_names, i));
175 61           git_array_clear(repo->reserved_names);
176              
177 61           git__free(repo->gitlink);
178 61           git__free(repo->gitdir);
179 61           git__free(repo->commondir);
180 61           git__free(repo->workdir);
181 61           git__free(repo->namespace);
182 61           git__free(repo->ident_name);
183 61           git__free(repo->ident_email);
184              
185 61           git__memzero(repo, sizeof(*repo));
186 61           git__free(repo);
187             }
188              
189             /*
190             * Git repository open methods
191             *
192             * Open a repository object from its path
193             */
194 70           static int is_valid_repository_path(bool *out, git_buf *repository_path, git_buf *common_path)
195             {
196             int error;
197              
198 70           *out = false;
199              
200             /* Check if we have a separate commondir (e.g. we have a
201             * worktree) */
202 70 100         if (git_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) {
203 5           git_buf common_link = GIT_BUF_INIT;
204              
205 5 50         if ((error = git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE)) < 0 ||
    50          
206 5           (error = git_futils_readbuffer(&common_link, common_link.ptr)) < 0)
207 0           return error;
208              
209 5           git_buf_rtrim(&common_link);
210 5 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 5           git_buf_swap(common_path, &common_link);
215             }
216              
217 5           git_buf_dispose(&common_link);
218             }
219             else {
220 65 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 70 100         if (git_buf_rfind(common_path, '/') != (ssize_t)common_path->size - 1)
226 60 50         if ((error = git_buf_putc(common_path, '/')) < 0)
227 0           return error;
228              
229             /* Ensure HEAD file exists */
230 70 100         if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false)
231 6           return 0;
232             /* Check files in common dir */
233 64 50         if (git_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false)
234 0           return 0;
235 64 50         if (git_path_contains_dir(common_path, GIT_REFS_DIR) == false)
236 0           return 0;
237              
238 64           *out = true;
239 64           return 0;
240             }
241              
242 63           static git_repository *repository_alloc(void)
243             {
244 63           git_repository *repo = git__calloc(1, sizeof(git_repository));
245              
246 126           if (repo == NULL ||
247 63           git_cache_init(&repo->objects) < 0)
248             goto on_error;
249              
250 63           git_array_init_to_size(repo->reserved_names, 4);
251 63 50         if (!repo->reserved_names.ptr)
252 0           goto on_error;
253              
254             /* set all the entries in the configmap cache to `unset` */
255 63           git_repository__configmap_lookup_cache_clear(repo);
256              
257 63           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 63           static int load_config_data(git_repository *repo, const git_config *config)
281             {
282             int is_bare;
283              
284 63           int err = git_config_get_bool(&is_bare, config, "core.bare");
285 63 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 63 50         if (err != GIT_ENOTFOUND)
290 63 100         repo->is_bare = is_bare && !repo->is_worktree;
    50          
291             else
292 0           repo->is_bare = 0;
293              
294 63           return 0;
295             }
296              
297 63           static int load_workdir(git_repository *repo, git_config *config, git_buf *parent_path)
298             {
299             int error;
300             git_config_entry *ce;
301 63           git_buf worktree = GIT_BUF_INIT;
302 63           git_buf path = GIT_BUF_INIT;
303              
304 63 100         if (repo->is_bare)
305 8           return 0;
306              
307 55 50         if ((error = git_config__lookup_entry(
308             &ce, config, "core.worktree", false)) < 0)
309 0           return error;
310              
311 55 100         if (repo->is_worktree) {
312 5           char *gitlink = git_worktree__read_link(repo->gitdir, GIT_GITDIR_FILE);
313 5 50         if (!gitlink) {
314 0           error = -1;
315 0           goto cleanup;
316             }
317              
318 5           git_buf_attach(&worktree, gitlink, 0);
319              
320 10           if ((git_path_dirname_r(&worktree, worktree.ptr)) < 0 ||
321 5           git_path_to_dir(&worktree) < 0) {
322 0           error = -1;
323 0           goto cleanup;
324             }
325              
326 5           repo->workdir = git_buf_detach(&worktree);
327             }
328 50 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 50 50         else if (parent_path && git_path_isdir(parent_path->ptr))
    50          
336 50           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 55 50         GIT_ERROR_CHECK_ALLOC(repo->workdir);
348             cleanup:
349 55           git_buf_dispose(&path);
350 55           git_config_entry_free(ce);
351 63           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 5           static int read_gitfile(git_buf *path_out, const char *file_path)
412             {
413 5           int error = 0;
414 5           git_buf file = GIT_BUF_INIT;
415 5           size_t prefix_len = strlen(GIT_FILE_CONTENT_PREFIX);
416              
417 5 50         assert(path_out && file_path);
    50          
418              
419 5 50         if (git_futils_readbuffer(&file, file_path) < 0)
420 0           return -1;
421              
422 5           git_buf_rtrim(&file);
423             /* apparently on Windows, some people use backslashes in paths */
424             git_path_mkposix(file.ptr);
425              
426 10           if (git_buf_len(&file) <= prefix_len ||
427 5           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 5 50         else if ((error = git_path_dirname_r(path_out, file_path)) >= 0) {
434 5           const char *gitlink = git_buf_cstr(&file) + prefix_len;
435 10 50         while (*gitlink && git__isspace(*gitlink)) gitlink++;
    100          
436              
437 5           error = git_path_prettify_dir(
438             path_out, gitlink, git_buf_cstr(path_out));
439             }
440              
441 5           git_buf_dispose(&file);
442 5           return error;
443             }
444              
445 64           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 64           git_buf path = GIT_BUF_INIT;
455 64           git_buf repo_link = GIT_BUF_INIT;
456 64           git_buf common_link = GIT_BUF_INIT;
457             struct stat st;
458 64           dev_t initial_device = 0;
459             int min_iterations;
460             bool in_dot_git, is_valid;
461 64           size_t ceiling_offset = 0;
462             int error;
463              
464 64           git_buf_clear(gitdir_path);
465              
466 64           error = git_path_prettify(&path, start_path, NULL);
467 64 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 64 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 64           in_dot_git = false;
482 64           min_iterations = 2;
483             }
484              
485             for (;;) {
486 96 50         if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT)) {
487 96 100         if (!in_dot_git) {
488 65 50         if ((error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0)
489 0           goto out;
490             }
491 96           in_dot_git = !in_dot_git;
492             }
493              
494 96 100         if (p_stat(path.ptr, &st) == 0) {
495             /* check that we have not crossed device boundaries */
496 65 100         if (initial_device == 0)
497 64           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 65 100         if (S_ISDIR(st.st_mode)) {
503 60 50         if ((error = is_valid_repository_path(&is_valid, &path, &common_link)) < 0)
504 0           goto out;
505              
506 60 100         if (is_valid) {
507 59 50         if ((error = git_path_to_dir(&path)) < 0 ||
    50          
508 59           (error = git_buf_set(gitdir_path, path.ptr, path.size)) < 0)
509             goto out;
510              
511 59 100         if (gitlink_path)
512 58 50         if ((error = git_buf_attach(gitlink_path, git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0)) < 0)
513 0           goto out;
514 59 100         if (commondir_path)
515 58           git_buf_swap(&common_link, commondir_path);
516              
517 59           break;
518             }
519 5 50         } else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) {
    50          
520 5 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 5 50         if (is_valid) {
525 5           git_buf_swap(gitdir_path, &repo_link);
526              
527 5 50         if (gitlink_path)
528 5 50         if ((error = git_buf_put(gitlink_path, path.ptr, path.size)) < 0)
529 0           goto out;
530 5 50         if (commondir_path)
531 5           git_buf_swap(&common_link, commondir_path);
532             }
533 5           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 32 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 32 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 32 100         if (min_iterations == 0 &&
    50          
550 1 50         (path.ptr[ceiling_offset] == 0 || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))
551             break;
552 32           }
553              
554 64 100         if (workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
    50          
555 63 50         if (!git_buf_len(gitdir_path))
556 0           git_buf_clear(workdir_path);
557 63 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 64 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 64           git_buf_dispose(&path);
572 64           git_buf_dispose(&repo_link);
573 64           git_buf_dispose(&common_link);
574 64           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 63           static int repo_is_worktree(unsigned *out, const git_repository *repo)
784             {
785 63           git_buf gitdir_link = GIT_BUF_INIT;
786             int error;
787              
788             /* Worktrees cannot have the same commondir and gitdir */
789 63 50         if (repo->commondir && repo->gitdir
    50          
790 63 100         && !strcmp(repo->commondir, repo->gitdir)) {
791 58           *out = 0;
792 58           return 0;
793             }
794              
795 5 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 5           *out = !!git_path_exists(gitdir_link.ptr);
801              
802 5           git_buf_dispose(&gitdir_link);
803 63           return error;
804             }
805              
806 63           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 63           git_buf gitdir = GIT_BUF_INIT, workdir = GIT_BUF_INIT,
815 63           gitlink = GIT_BUF_INIT, commondir = GIT_BUF_INIT;
816 63           git_repository *repo = NULL;
817 63           git_config *config = NULL;
818 63           int version = 0;
819              
820 63 50         if (flags & GIT_REPOSITORY_OPEN_FROM_ENV)
821 0           return _git_repository_open_ext_from_env(repo_ptr, start_path);
822              
823 63 50         if (repo_ptr)
824 63           *repo_ptr = NULL;
825              
826 63           error = find_repo(
827             &gitdir, &workdir, &gitlink, &commondir, start_path, flags, ceiling_dirs);
828              
829 63 50         if (error < 0 || !repo_ptr)
    50          
830             goto cleanup;
831              
832 63           repo = repository_alloc();
833 63 50         GIT_ERROR_CHECK_ALLOC(repo);
834              
835 63           repo->gitdir = git_buf_detach(&gitdir);
836 63 50         GIT_ERROR_CHECK_ALLOC(repo->gitdir);
837              
838 63 100         if (gitlink.size) {
839 5           repo->gitlink = git_buf_detach(&gitlink);
840 5 50         GIT_ERROR_CHECK_ALLOC(repo->gitlink);
841             }
842 63 50         if (commondir.size) {
843 63           repo->commondir = git_buf_detach(&commondir);
844 63 50         GIT_ERROR_CHECK_ALLOC(repo->commondir);
845             }
846              
847 63 50         if ((error = repo_is_worktree(&is_worktree, repo)) < 0)
848 0           goto cleanup;
849 63           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 63           error = git_repository_config_snapshot(&config, repo);
857 63 50         if (error < 0 && error != GIT_ENOTFOUND)
    0          
858 0           goto cleanup;
859              
860 63 50         if (config && (error = check_repositoryformatversion(&version, config)) < 0)
    50          
861 0           goto cleanup;
862              
863 63 50         if ((error = check_extensions(config, version) < 0))
864 0           goto cleanup;
865              
866 63 50         if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0)
867 0           repo->is_bare = 1;
868             else {
869              
870 63 50         if (config &&
    50          
871 63           ((error = load_config_data(repo, config)) < 0 ||
872 63           (error = load_workdir(repo, config, &workdir)) < 0))
873             goto cleanup;
874             }
875              
876             cleanup:
877 63           git_buf_dispose(&gitdir);
878 63           git_buf_dispose(&workdir);
879 63           git_buf_dispose(&gitlink);
880 63           git_buf_dispose(&commondir);
881 63           git_config_free(config);
882              
883 63 50         if (error < 0)
884 0           git_repository_free(repo);
885 63 50         else if (repo_ptr)
886 63           *repo_ptr = repo;
887              
888 63           return error;
889             }
890              
891 63           int git_repository_open(git_repository **repo_out, const char *path)
892             {
893 63           return git_repository_open_ext(
894             repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL);
895             }
896              
897 2           int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *wt)
898             {
899 2           git_buf path = GIT_BUF_INIT;
900 2           git_repository *repo = NULL;
901             size_t len;
902             int err;
903              
904 2 50         assert(repo_out && wt);
    50          
905              
906 2           *repo_out = NULL;
907 2           len = strlen(wt->gitlink_path);
908              
909 2 50         if (len <= 4 || strcasecmp(wt->gitlink_path + len - 4, ".git")) {
    50          
910 0           err = -1;
911 0           goto out;
912             }
913              
914 2 50         if ((err = git_buf_set(&path, wt->gitlink_path, len - 4)) < 0)
915 0           goto out;
916              
917 2 50         if ((err = git_repository_open(&repo, path.ptr)) < 0)
918 0           goto out;
919              
920 2           *repo_out = repo;
921              
922             out:
923 2           git_buf_dispose(&path);
924              
925 2           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 63           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 63           git_buf config_path = GIT_BUF_INIT;
966 63           git_config *cfg = NULL;
967              
968 63 50         assert(out);
969              
970 63 50         if ((error = git_config_new(&cfg)) < 0)
971 0           return error;
972              
973 63 50         if (repo) {
974 63 50         if ((error = git_repository_item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0)
975 63           error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, repo, 0);
976              
977 63 50         if (error && error != GIT_ENOTFOUND)
    0          
978 0           goto on_error;
979              
980 63           git_buf_dispose(&config_path);
981             }
982              
983 63 50         if (global_config_path != NULL &&
    50          
984 63           (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 63 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 63 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 63 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 63           git_error_clear(); /* clear any lingering ENOTFOUND errors */
1008              
1009 63           *out = cfg;
1010 63           return 0;
1011              
1012             on_error:
1013 0           git_buf_dispose(&config_path);
1014 0           git_config_free(cfg);
1015 0           *out = NULL;
1016 63           return error;
1017             }
1018              
1019 252           static const char *path_unless_empty(git_buf *buf)
1020             {
1021 252 100         return git_buf_len(buf) > 0 ? git_buf_cstr(buf) : NULL;
1022             }
1023              
1024 992           int git_repository_config__weakptr(git_config **out, git_repository *repo)
1025             {
1026 992           int error = 0;
1027              
1028 992 100         if (repo->_config == NULL) {
1029 63           git_buf global_buf = GIT_BUF_INIT;
1030 63           git_buf xdg_buf = GIT_BUF_INIT;
1031 63           git_buf system_buf = GIT_BUF_INIT;
1032 63           git_buf programdata_buf = GIT_BUF_INIT;
1033             git_config *config;
1034              
1035 63           git_config_find_global(&global_buf);
1036 63           git_config_find_xdg(&xdg_buf);
1037 63           git_config_find_system(&system_buf);
1038 63           git_config_find_programdata(&programdata_buf);
1039              
1040             /* If there is no global file, open a backend for it anyway */
1041 63 50         if (git_buf_len(&global_buf) == 0)
1042 63           git_config__global_location(&global_buf);
1043              
1044 63           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 63 50         if (!error) {
1051 63           GIT_REFCOUNT_OWN(config, repo);
1052              
1053 63           config = git__compare_and_swap(&repo->_config, NULL, config);
1054 63 50         if (config != NULL) {
1055 0           GIT_REFCOUNT_OWN(config, NULL);
1056 0           git_config_free(config);
1057             }
1058             }
1059              
1060 63           git_buf_dispose(&global_buf);
1061 63           git_buf_dispose(&xdg_buf);
1062 63           git_buf_dispose(&system_buf);
1063 63           git_buf_dispose(&programdata_buf);
1064             }
1065              
1066 992           *out = repo->_config;
1067 992           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 502           int git_repository_config_snapshot(git_config **out, git_repository *repo)
1080             {
1081             int error;
1082             git_config *weak;
1083              
1084 502 50         if ((error = git_repository_config__weakptr(&weak, repo)) < 0)
1085 0           return error;
1086              
1087 502           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 2358           int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
1098             {
1099 2358           int error = 0;
1100              
1101 2358 50         assert(repo && out);
    50          
1102              
1103 2358 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 2358           *out = repo->_odb;
1130 2358           return error;
1131             }
1132              
1133 164           int git_repository_odb(git_odb **out, git_repository *repo)
1134             {
1135 164 50         if (git_repository_odb__weakptr(out, repo) < 0)
1136 0           return -1;
1137              
1138 164           GIT_REFCOUNT_INC(*out);
1139 164           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 1321           int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo)
1150             {
1151 1321           int error = 0;
1152              
1153 1321 50         assert(out && repo);
    50          
1154              
1155 1321 100         if (repo->_refdb == NULL) {
1156             git_refdb *refdb;
1157              
1158 54           error = git_refdb_open(&refdb, repo);
1159 54 50         if (!error) {
1160 54           GIT_REFCOUNT_OWN(refdb, repo);
1161              
1162 54           refdb = git__compare_and_swap(&repo->_refdb, NULL, refdb);
1163 54 50         if (refdb != NULL) {
1164 0           GIT_REFCOUNT_OWN(refdb, NULL);
1165 54           git_refdb_free(refdb);
1166             }
1167             }
1168             }
1169              
1170 1321           *out = repo->_refdb;
1171 1321           return error;
1172             }
1173              
1174 83           int git_repository_refdb(git_refdb **out, git_repository *repo)
1175             {
1176 83 50         if (git_repository_refdb__weakptr(out, repo) < 0)
1177 0           return -1;
1178              
1179 83           GIT_REFCOUNT_INC(*out);
1180 83           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 3116           int git_repository_index__weakptr(git_index **out, git_repository *repo)
1191             {
1192 3116           int error = 0;
1193              
1194 3116 50         assert(out && repo);
    50          
1195              
1196 3116 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 3116           *out = repo->_index;
1221 3116           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 63           static int check_repositoryformatversion(int *version, git_config *config)
1360             {
1361             int error;
1362              
1363 63           error = git_config_get_int32(version, config, "core.repositoryformatversion");
1364             /* git ignores this if the config variable isn't there */
1365 63 50         if (error == GIT_ENOTFOUND)
1366 0           return 0;
1367              
1368 63 50         if (error < 0)
1369 0           return -1;
1370              
1371 63 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 63           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 68           static int check_extensions(git_config *config, int version)
1393             {
1394 68 50         if (version < 1)
1395 68           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 0           int git_repository_head_detached_for_worktree(git_repository *repo, const char *name)
2181             {
2182 0           git_reference *ref = NULL;
2183             int error;
2184              
2185 0 0         assert(repo && name);
    0          
2186              
2187 0 0         if ((error = git_repository_head_for_worktree(&ref, repo, name)) < 0)
2188 0           goto out;
2189              
2190 0           error = (git_reference_type(ref) != GIT_REFERENCE_SYMBOLIC);
2191             out:
2192 0           git_reference_free(ref);
2193              
2194 0           return error;
2195             }
2196              
2197 265           int git_repository_head(git_reference **head_out, git_repository *repo)
2198             {
2199             git_reference *head;
2200             int error;
2201              
2202 265 50         assert(head_out);
2203              
2204 265 50         if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
2205 0           return error;
2206              
2207 265 100         if (git_reference_type(head) == GIT_REFERENCE_DIRECT) {
2208 21           *head_out = head;
2209 21           return 0;
2210             }
2211              
2212 244           error = git_reference_lookup_resolved(head_out, repo, git_reference_symbolic_target(head), -1);
2213 244           git_reference_free(head);
2214              
2215 265 100         return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error;
2216             }
2217              
2218 1           int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name)
2219             {
2220 1           git_repository *worktree_repo = NULL;
2221 1           git_worktree *worktree = NULL;
2222 1           git_reference *head = NULL;
2223             int error;
2224              
2225 1 50         assert(out && repo && name);
    50          
    50          
2226              
2227 1           *out = NULL;
2228              
2229 1 50         if ((error = git_worktree_lookup(&worktree, repo, name)) < 0 ||
    50          
2230 1 50         (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0 ||
2231 1           (error = git_reference_lookup(&head, worktree_repo, GIT_HEAD_FILE)) < 0)
2232             goto out;
2233              
2234 1 50         if (git_reference_type(head) != GIT_REFERENCE_DIRECT) {
2235 1 50         if ((error = git_reference_lookup_resolved(out, worktree_repo, git_reference_symbolic_target(head), -1)) < 0)
2236 0           goto out;
2237             } else {
2238 0           *out = head;
2239 0           head = NULL;
2240             }
2241              
2242             out:
2243 1           git_reference_free(head);
2244 1           git_worktree_free(worktree);
2245 1           git_repository_free(worktree_repo);
2246 1           return error;
2247             }
2248              
2249 18           int git_repository_foreach_worktree(git_repository *repo,
2250             git_repository_foreach_worktree_cb cb,
2251             void *payload)
2252             {
2253 18           git_strarray worktrees = {0};
2254 18           git_repository *worktree_repo = NULL;
2255 18           git_worktree *worktree = NULL;
2256             int error;
2257             size_t i;
2258              
2259 36           if ((error = git_repository_open(&worktree_repo, repo->commondir)) < 0 ||
2260 18           (error = cb(worktree_repo, payload) != 0))
2261             goto out;
2262              
2263 18           git_repository_free(worktree_repo);
2264 18           worktree_repo = NULL;
2265              
2266 18 50         if ((error = git_worktree_list(&worktrees, repo)) < 0)
2267 0           goto out;
2268              
2269 18 50         for (i = 0; i < worktrees.count; i++) {
2270 0           git_repository_free(worktree_repo);
2271 0           worktree_repo = NULL;
2272 0           git_worktree_free(worktree);
2273 0           worktree = NULL;
2274              
2275 0 0         if ((error = git_worktree_lookup(&worktree, repo, worktrees.strings[i]) < 0) ||
    0          
2276 0           (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0) {
2277 0 0         if (error != GIT_ENOTFOUND)
2278 0           goto out;
2279 0           error = 0;
2280 0           continue;
2281             }
2282              
2283 0 0         if ((error = cb(worktree_repo, payload)) != 0)
2284 0           goto out;
2285             }
2286              
2287             out:
2288 18           git_strarray_dispose(&worktrees);
2289 18           git_repository_free(worktree_repo);
2290 18           git_worktree_free(worktree);
2291 18           return error;
2292             }
2293              
2294 0           int git_repository_head_unborn(git_repository *repo)
2295             {
2296 0           git_reference *ref = NULL;
2297             int error;
2298              
2299 0           error = git_repository_head(&ref, repo);
2300 0           git_reference_free(ref);
2301              
2302 0 0         if (error == GIT_EUNBORNBRANCH) {
2303 0           git_error_clear();
2304 0           return 1;
2305             }
2306              
2307 0 0         if (error < 0)
2308 0           return -1;
2309              
2310 0           return 0;
2311             }
2312              
2313 0           static int at_least_one_cb(const char *refname, void *payload)
2314             {
2315             GIT_UNUSED(refname);
2316             GIT_UNUSED(payload);
2317 0           return GIT_PASSTHROUGH;
2318             }
2319              
2320 2           static int repo_contains_no_reference(git_repository *repo)
2321             {
2322 2           int error = git_reference_foreach_name(repo, &at_least_one_cb, NULL);
2323              
2324 2 50         if (error == GIT_PASSTHROUGH)
2325 0           return 0;
2326              
2327 2 50         if (!error)
2328 2           return 1;
2329              
2330 0           return error;
2331             }
2332              
2333 2           int git_repository_is_empty(git_repository *repo)
2334             {
2335 2           git_reference *head = NULL;
2336 2           int is_empty = 0;
2337              
2338 2 50         if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0)
2339 0           return -1;
2340              
2341 2 50         if (git_reference_type(head) == GIT_REFERENCE_SYMBOLIC)
2342 2           is_empty =
2343 2           (strcmp(git_reference_symbolic_target(head),
2344 4           GIT_REFS_HEADS_DIR "master") == 0) &&
2345 2           repo_contains_no_reference(repo);
2346              
2347 2           git_reference_free(head);
2348              
2349 2           return is_empty;
2350             }
2351              
2352 1468           static const char *resolved_parent_path(const git_repository *repo, git_repository_item_t item, git_repository_item_t fallback)
2353             {
2354             const char *parent;
2355              
2356 1468           switch (item) {
2357             case GIT_REPOSITORY_ITEM_GITDIR:
2358 0           parent = git_repository_path(repo);
2359 0           break;
2360             case GIT_REPOSITORY_ITEM_WORKDIR:
2361 0           parent = git_repository_workdir(repo);
2362 0           break;
2363             case GIT_REPOSITORY_ITEM_COMMONDIR:
2364 1468           parent = git_repository_commondir(repo);
2365 1468           break;
2366             default:
2367 0           git_error_set(GIT_ERROR_INVALID, "invalid item directory");
2368 0           return NULL;
2369             }
2370 1468 50         if (!parent && fallback != GIT_REPOSITORY_ITEM__LAST)
    0          
2371 0           return resolved_parent_path(repo, fallback, GIT_REPOSITORY_ITEM__LAST);
2372              
2373 1468           return parent;
2374             }
2375              
2376 1468           int git_repository_item_path(git_buf *out, const git_repository *repo, git_repository_item_t item)
2377             {
2378 1468           const char *parent = resolved_parent_path(repo, items[item].parent, items[item].fallback);
2379 1468 50         if (parent == NULL) {
2380 0           git_error_set(GIT_ERROR_INVALID, "path cannot exist in repository");
2381 0           return GIT_ENOTFOUND;
2382             }
2383              
2384 1468 50         if (git_buf_sets(out, parent) < 0)
2385 0           return -1;
2386              
2387 1468 50         if (items[item].name) {
2388 1468 50         if (git_buf_joinpath(out, parent, items[item].name) < 0)
2389 0           return -1;
2390             }
2391              
2392 1468 100         if (items[item].directory) {
2393 1405 50         if (git_path_to_dir(out) < 0)
2394 0           return -1;
2395             }
2396              
2397 1468           return 0;
2398             }
2399              
2400 30           const char *git_repository_path(const git_repository *repo)
2401             {
2402 30 50         assert(repo);
2403 30           return repo->gitdir;
2404             }
2405              
2406 8017           const char *git_repository_workdir(const git_repository *repo)
2407             {
2408 8017 50         assert(repo);
2409              
2410 8017 50         if (repo->is_bare)
2411 0           return NULL;
2412              
2413 8017           return repo->workdir;
2414             }
2415              
2416 1471           const char *git_repository_commondir(const git_repository *repo)
2417             {
2418 1471 50         assert(repo);
2419 1471           return repo->commondir;
2420             }
2421              
2422 2           int git_repository_set_workdir(
2423             git_repository *repo, const char *workdir, int update_gitlink)
2424             {
2425 2           int error = 0;
2426 2           git_buf path = GIT_BUF_INIT;
2427              
2428 2 50         assert(repo && workdir);
    50          
2429              
2430 2 50         if (git_path_prettify_dir(&path, workdir, NULL) < 0)
2431 0           return -1;
2432              
2433 2 50         if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0)
    50          
2434 2           return 0;
2435              
2436 0 0         if (update_gitlink) {
2437             git_config *config;
2438              
2439 0 0         if (git_repository_config__weakptr(&config, repo) < 0)
2440 0           return -1;
2441              
2442 0           error = repo_write_gitlink(path.ptr, git_repository_path(repo), false);
2443              
2444             /* passthrough error means gitlink is unnecessary */
2445 0 0         if (error == GIT_PASSTHROUGH)
2446 0           error = git_config_delete_entry(config, "core.worktree");
2447 0 0         else if (!error)
2448 0           error = git_config_set_string(config, "core.worktree", path.ptr);
2449              
2450 0 0         if (!error)
2451 0           error = git_config_set_bool(config, "core.bare", false);
2452             }
2453              
2454 0 0         if (!error) {
2455 0           char *old_workdir = repo->workdir;
2456              
2457 0           repo->workdir = git_buf_detach(&path);
2458 0           repo->is_bare = 0;
2459              
2460 0           git__free(old_workdir);
2461             }
2462              
2463 2           return error;
2464             }
2465              
2466 1083           int git_repository_is_bare(const git_repository *repo)
2467             {
2468 1083 50         assert(repo);
2469 1083           return repo->is_bare;
2470             }
2471              
2472 2           int git_repository_is_worktree(const git_repository *repo)
2473             {
2474 2 50         assert(repo);
2475 2           return repo->is_worktree;
2476             }
2477              
2478 0           int git_repository_set_bare(git_repository *repo)
2479             {
2480             int error;
2481             git_config *config;
2482              
2483 0 0         assert(repo);
2484              
2485 0 0         if (repo->is_bare)
2486 0           return 0;
2487              
2488 0 0         if ((error = git_repository_config__weakptr(&config, repo)) < 0)
2489 0           return error;
2490              
2491 0 0         if ((error = git_config_set_bool(config, "core.bare", true)) < 0)
2492 0           return error;
2493              
2494 0 0         if ((error = git_config__update_entry(config, "core.worktree", NULL, true, true)) < 0)
2495 0           return error;
2496              
2497 0           git__free(repo->workdir);
2498 0           repo->workdir = NULL;
2499 0           repo->is_bare = 1;
2500              
2501 0           return 0;
2502             }
2503              
2504 100           int git_repository_head_tree(git_tree **tree, git_repository *repo)
2505             {
2506             git_reference *head;
2507             git_object *obj;
2508             int error;
2509              
2510 100 100         if ((error = git_repository_head(&head, repo)) < 0)
2511 14           return error;
2512              
2513 86 50         if ((error = git_reference_peel(&obj, head, GIT_OBJECT_TREE)) < 0)
2514 0           goto cleanup;
2515              
2516 86           *tree = (git_tree *)obj;
2517              
2518             cleanup:
2519 86           git_reference_free(head);
2520 100           return error;
2521             }
2522              
2523 7           int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head)
2524             {
2525 7           git_filebuf file = GIT_FILEBUF_INIT;
2526 7           git_buf file_path = GIT_BUF_INIT;
2527             char orig_head_str[GIT_OID_HEXSZ];
2528 7           int error = 0;
2529              
2530 7           git_oid_fmt(orig_head_str, orig_head);
2531              
2532 7 50         if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_ORIG_HEAD_FILE)) == 0 &&
    50          
2533 7 50         (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) == 0 &&
2534             (error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0)
2535 7           error = git_filebuf_commit(&file);
2536              
2537 7 50         if (error < 0)
2538 0           git_filebuf_cleanup(&file);
2539              
2540 7           git_buf_dispose(&file_path);
2541              
2542 7           return error;
2543             }
2544              
2545 1           int git_repository_message(git_buf *out, git_repository *repo)
2546             {
2547 1           git_buf path = GIT_BUF_INIT;
2548             struct stat st;
2549             int error;
2550              
2551 1           git_buf_sanitize(out);
2552              
2553 1 50         if (git_buf_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0)
2554 0           return -1;
2555              
2556 1 50         if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) {
2557 0 0         if (errno == ENOENT)
2558 0           error = GIT_ENOTFOUND;
2559 0           git_error_set(GIT_ERROR_OS, "could not access message file");
2560             } else {
2561 1           error = git_futils_readbuffer(out, git_buf_cstr(&path));
2562             }
2563              
2564 1           git_buf_dispose(&path);
2565              
2566 1           return error;
2567             }
2568              
2569 0           int git_repository_message_remove(git_repository *repo)
2570             {
2571 0           git_buf path = GIT_BUF_INIT;
2572             int error;
2573              
2574 0 0         if (git_buf_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0)
2575 0           return -1;
2576              
2577 0           error = p_unlink(git_buf_cstr(&path));
2578 0           git_buf_dispose(&path);
2579              
2580 0           return error;
2581             }
2582              
2583 0           int git_repository_hashfile(
2584             git_oid *out,
2585             git_repository *repo,
2586             const char *path,
2587             git_object_t type,
2588             const char *as_path)
2589             {
2590             int error;
2591 0           git_filter_list *fl = NULL;
2592 0           git_file fd = -1;
2593             uint64_t len;
2594 0           git_buf full_path = GIT_BUF_INIT;
2595              
2596 0 0         assert(out && path && repo); /* as_path can be NULL */
    0          
    0          
2597              
2598             /* At some point, it would be nice if repo could be NULL to just
2599             * apply filter rules defined in system and global files, but for
2600             * now that is not possible because git_filters_load() needs it.
2601             */
2602              
2603 0           error = git_path_join_unrooted(
2604             &full_path, path, git_repository_workdir(repo), NULL);
2605 0 0         if (error < 0)
2606 0           return error;
2607              
2608 0 0         if (!as_path)
2609 0           as_path = path;
2610              
2611             /* passing empty string for "as_path" indicated --no-filters */
2612 0 0         if (strlen(as_path) > 0) {
2613 0           error = git_filter_list_load(
2614             &fl, repo, NULL, as_path,
2615             GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT);
2616 0 0         if (error < 0)
2617 0           return error;
2618             } else {
2619 0           error = 0;
2620             }
2621              
2622             /* at this point, error is a count of the number of loaded filters */
2623              
2624 0           fd = git_futils_open_ro(full_path.ptr);
2625 0 0         if (fd < 0) {
2626 0           error = fd;
2627 0           goto cleanup;
2628             }
2629              
2630 0 0         if ((error = git_futils_filesize(&len, fd)) < 0)
2631 0           goto cleanup;
2632              
2633 0 0         if (!git__is_sizet(len)) {
2634 0           git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems");
2635 0           error = -1;
2636 0           goto cleanup;
2637             }
2638              
2639 0           error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, fl);
2640              
2641             cleanup:
2642 0 0         if (fd >= 0)
2643 0           p_close(fd);
2644 0           git_filter_list_free(fl);
2645 0           git_buf_dispose(&full_path);
2646              
2647 0           return error;
2648             }
2649              
2650 20           static int checkout_message(git_buf *out, git_reference *old, const char *new)
2651             {
2652 20           git_buf_puts(out, "checkout: moving from ");
2653              
2654 20 100         if (git_reference_type(old) == GIT_REFERENCE_SYMBOLIC)
2655 19           git_buf_puts(out, git_reference__shorthand(git_reference_symbolic_target(old)));
2656             else
2657 1           git_buf_puts(out, git_oid_tostr_s(git_reference_target(old)));
2658              
2659 20           git_buf_puts(out, " to ");
2660              
2661 21           if (git_reference__is_branch(new) ||
2662 2 50         git_reference__is_tag(new) ||
2663 1           git_reference__is_remote(new))
2664 19           git_buf_puts(out, git_reference__shorthand(new));
2665             else
2666 1           git_buf_puts(out, new);
2667              
2668 20 50         if (git_buf_oom(out))
2669 0           return -1;
2670              
2671 20           return 0;
2672             }
2673              
2674 1           static int detach(git_repository *repo, const git_oid *id, const char *new)
2675             {
2676             int error;
2677 1           git_buf log_message = GIT_BUF_INIT;
2678 1           git_object *object = NULL, *peeled = NULL;
2679 1           git_reference *new_head = NULL, *current = NULL;
2680              
2681 1 50         assert(repo && id);
    50          
2682              
2683 1 50         if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0)
2684 0           return error;
2685              
2686 1 50         if ((error = git_object_lookup(&object, repo, id, GIT_OBJECT_ANY)) < 0)
2687 0           goto cleanup;
2688              
2689 1 50         if ((error = git_object_peel(&peeled, object, GIT_OBJECT_COMMIT)) < 0)
2690 0           goto cleanup;
2691              
2692 1 50         if (new == NULL)
2693 1           new = git_oid_tostr_s(git_object_id(peeled));
2694              
2695 1 50         if ((error = checkout_message(&log_message, current, new)) < 0)
2696 0           goto cleanup;
2697              
2698 1           error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message));
2699              
2700             cleanup:
2701 1           git_buf_dispose(&log_message);
2702 1           git_object_free(object);
2703 1           git_object_free(peeled);
2704 1           git_reference_free(current);
2705 1           git_reference_free(new_head);
2706 1           return error;
2707             }
2708              
2709 19           int git_repository_set_head(
2710             git_repository* repo,
2711             const char* refname)
2712             {
2713 19           git_reference *ref = NULL, *current = NULL, *new_head = NULL;
2714 19           git_buf log_message = GIT_BUF_INIT;
2715             int error;
2716              
2717 19 50         assert(repo && refname);
    50          
2718              
2719 19 50         if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0)
2720 0           return error;
2721              
2722 19 50         if ((error = checkout_message(&log_message, current, refname)) < 0)
2723 0           goto cleanup;
2724              
2725 19           error = git_reference_lookup(&ref, repo, refname);
2726 19 50         if (error < 0 && error != GIT_ENOTFOUND)
    0          
2727 0           goto cleanup;
2728              
2729 36 50         if (ref && current->type == GIT_REFERENCE_SYMBOLIC && git__strcmp(current->target.symbolic, ref->name) &&
    100          
2730 34 50         git_reference_is_branch(ref) && git_branch_is_checked_out(ref)) {
2731 0           git_error_set(GIT_ERROR_REPOSITORY, "cannot set HEAD to reference '%s' as it is the current HEAD "
2732             "of a linked repository.", git_reference_name(ref));
2733 0           error = -1;
2734 0           goto cleanup;
2735             }
2736              
2737 19 50         if (!error) {
2738 19 50         if (git_reference_is_branch(ref)) {
2739 19           error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE,
2740             git_reference_name(ref), true, git_buf_cstr(&log_message));
2741             } else {
2742 19 0         error = detach(repo, git_reference_target(ref),
2743 0 0         git_reference_is_tag(ref) || git_reference_is_remote(ref) ? refname : NULL);
2744             }
2745 0 0         } else if (git_reference__is_branch(refname)) {
2746 0           error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname,
2747             true, git_buf_cstr(&log_message));
2748             }
2749              
2750             cleanup:
2751 19           git_buf_dispose(&log_message);
2752 19           git_reference_free(current);
2753 19           git_reference_free(ref);
2754 19           git_reference_free(new_head);
2755 19           return error;
2756             }
2757              
2758 1           int git_repository_set_head_detached(
2759             git_repository* repo,
2760             const git_oid* commitish)
2761             {
2762 1           return detach(repo, commitish, NULL);
2763             }
2764              
2765 0           int git_repository_set_head_detached_from_annotated(
2766             git_repository *repo,
2767             const git_annotated_commit *commitish)
2768             {
2769 0 0         assert(repo && commitish);
    0          
2770              
2771 0           return detach(repo, git_annotated_commit_id(commitish), commitish->description);
2772             }
2773              
2774 0           int git_repository_detach_head(git_repository* repo)
2775             {
2776 0           git_reference *old_head = NULL, *new_head = NULL, *current = NULL;
2777 0           git_object *object = NULL;
2778 0           git_buf log_message = GIT_BUF_INIT;
2779             int error;
2780              
2781 0 0         assert(repo);
2782              
2783 0 0         if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0)
2784 0           return error;
2785              
2786 0 0         if ((error = git_repository_head(&old_head, repo)) < 0)
2787 0           goto cleanup;
2788              
2789 0 0         if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJECT_COMMIT)) < 0)
2790 0           goto cleanup;
2791              
2792 0 0         if ((error = checkout_message(&log_message, current, git_oid_tostr_s(git_object_id(object)))) < 0)
2793 0           goto cleanup;
2794              
2795 0           error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head),
2796             1, git_buf_cstr(&log_message));
2797              
2798             cleanup:
2799 0           git_buf_dispose(&log_message);
2800 0           git_object_free(object);
2801 0           git_reference_free(old_head);
2802 0           git_reference_free(new_head);
2803 0           git_reference_free(current);
2804 0           return error;
2805             }
2806              
2807             /**
2808             * Loosely ported from git.git
2809             * https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh#L198-289
2810             */
2811 37           int git_repository_state(git_repository *repo)
2812             {
2813 37           git_buf repo_path = GIT_BUF_INIT;
2814 37           int state = GIT_REPOSITORY_STATE_NONE;
2815              
2816 37 50         assert(repo);
2817              
2818 37 50         if (git_buf_puts(&repo_path, repo->gitdir) < 0)
2819 0           return -1;
2820              
2821 37 100         if (git_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE))
2822 1           state = GIT_REPOSITORY_STATE_REBASE_INTERACTIVE;
2823 36 100         else if (git_path_contains_dir(&repo_path, GIT_REBASE_MERGE_DIR))
2824 3           state = GIT_REPOSITORY_STATE_REBASE_MERGE;
2825 33 100         else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_REBASING_FILE))
2826 1           state = GIT_REPOSITORY_STATE_REBASE;
2827 32 100         else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_APPLYING_FILE))
2828 1           state = GIT_REPOSITORY_STATE_APPLY_MAILBOX;
2829 31 100         else if (git_path_contains_dir(&repo_path, GIT_REBASE_APPLY_DIR))
2830 1           state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE;
2831 30 100         else if (git_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE))
2832 4           state = GIT_REPOSITORY_STATE_MERGE;
2833 26 100         else if (git_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE)) {
2834 2           state = GIT_REPOSITORY_STATE_REVERT;
2835 2 50         if (git_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) {
2836 2           state = GIT_REPOSITORY_STATE_REVERT_SEQUENCE;
2837             }
2838 24 100         } else if (git_path_contains_file(&repo_path, GIT_CHERRYPICK_HEAD_FILE)) {
2839 3           state = GIT_REPOSITORY_STATE_CHERRYPICK;
2840 3 50         if (git_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) {
2841 3           state = GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE;
2842             }
2843 21 100         } else if (git_path_contains_file(&repo_path, GIT_BISECT_LOG_FILE))
2844 1           state = GIT_REPOSITORY_STATE_BISECT;
2845              
2846 37           git_buf_dispose(&repo_path);
2847 37           return state;
2848             }
2849              
2850 20           int git_repository__cleanup_files(
2851             git_repository *repo, const char *files[], size_t files_len)
2852             {
2853 20           git_buf buf = GIT_BUF_INIT;
2854             size_t i;
2855             int error;
2856              
2857 193 50         for (error = 0, i = 0; !error && i < files_len; ++i) {
    100          
2858             const char *path;
2859              
2860 173 50         if (git_buf_joinpath(&buf, repo->gitdir, files[i]) < 0)
2861 0           return -1;
2862              
2863 173           path = git_buf_cstr(&buf);
2864              
2865 173 100         if (git_path_isfile(path)) {
2866 25           error = p_unlink(path);
2867 148 100         } else if (git_path_isdir(path)) {
2868 6           error = git_futils_rmdir_r(path, NULL,
2869             GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS);
2870             }
2871              
2872 173           git_buf_clear(&buf);
2873             }
2874              
2875 20           git_buf_dispose(&buf);
2876 20           return error;
2877             }
2878              
2879             static const char *state_files[] = {
2880             GIT_MERGE_HEAD_FILE,
2881             GIT_MERGE_MODE_FILE,
2882             GIT_MERGE_MSG_FILE,
2883             GIT_REVERT_HEAD_FILE,
2884             GIT_CHERRYPICK_HEAD_FILE,
2885             GIT_BISECT_LOG_FILE,
2886             GIT_REBASE_MERGE_DIR,
2887             GIT_REBASE_APPLY_DIR,
2888             GIT_SEQUENCER_DIR,
2889             };
2890              
2891 19           int git_repository_state_cleanup(git_repository *repo)
2892             {
2893 19 50         assert(repo);
2894              
2895 19           return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
2896             }
2897              
2898 0           int git_repository_is_shallow(git_repository *repo)
2899             {
2900 0           git_buf path = GIT_BUF_INIT;
2901             struct stat st;
2902             int error;
2903              
2904 0 0         if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0)
2905 0           return error;
2906              
2907 0           error = git_path_lstat(path.ptr, &st);
2908 0           git_buf_dispose(&path);
2909              
2910 0 0         if (error == GIT_ENOTFOUND) {
2911 0           git_error_clear();
2912 0           return 0;
2913             }
2914              
2915 0 0         if (error < 0)
2916 0           return error;
2917 0           return st.st_size == 0 ? 0 : 1;
2918             }
2919              
2920 0           int git_repository_init_options_init(
2921             git_repository_init_options *opts, unsigned int version)
2922             {
2923 0 0         GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2924             opts, version, git_repository_init_options,
2925             GIT_REPOSITORY_INIT_OPTIONS_INIT);
2926 0           return 0;
2927             }
2928              
2929             #ifndef GIT_DEPRECATE_HARD
2930 0           int git_repository_init_init_options(
2931             git_repository_init_options *opts, unsigned int version)
2932             {
2933 0           return git_repository_init_options_init(opts, version);
2934             }
2935             #endif
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 61           int git_repository_submodule_cache_clear(git_repository *repo)
2982             {
2983             git_submodule *sm;
2984 61 50         assert(repo);
2985 61 50         if (repo->submodule_cache == NULL) {
2986 61           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 61           return 0;
2994             }