Coverage Report

Created: 2025-06-09 06:06

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