]> git.proxmox.com Git - libgit2.git/blame - src/repository.c
attr: Change the attribute check macros
[libgit2.git] / src / repository.c
CommitLineData
3315782c 1/*
5e0de328 2 * Copyright (C) 2009-2012 the libgit2 contributors
3315782c 3 *
bb742ede
VM
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.
3315782c 6 */
e802d8cc 7#include <stdarg.h>
3315782c 8
44908fe7 9#include "git2/object.h"
d12299fe 10
3315782c
VM
11#include "common.h"
12#include "repository.h"
13#include "commit.h"
14#include "tag.h"
237da401 15#include "blob.h"
6fd195d7 16#include "fileops.h"
b22d1479 17#include "config.h"
9282e921 18#include "refs.h"
19
f2d6a23a 20#define GIT_OBJECTS_INFO_DIR GIT_OBJECTS_DIR "info/"
21#define GIT_OBJECTS_PACK_DIR GIT_OBJECTS_DIR "pack/"
40c44d2f 22
6a01b6bd 23#define GIT_FILE_CONTENT_PREFIX "gitdir: "
6a01b6bd 24
28990938 25#define GIT_BRANCH_MASTER "master"
26
5663e61a 27#define GIT_CONFIG_CORE_REPOSITORYFORMATVERSION "core.repositoryformatversion"
28#define GIT_REPOSITORYFORMATVERSION 0
691aa968 29
9462c471
VM
30static void drop_odb(git_repository *repo)
31{
32 if (repo->_odb != NULL) {
33 GIT_REFCOUNT_OWN(repo->_odb, NULL);
34 git_odb_free(repo->_odb);
35 repo->_odb = NULL;
eb2f3b47 36 }
9462c471 37}
691aa968 38
9462c471
VM
39static void drop_config(git_repository *repo)
40{
41 if (repo->_config != NULL) {
42 GIT_REFCOUNT_OWN(repo->_config, NULL);
43 git_config_free(repo->_config);
44 repo->_config = NULL;
eb2f3b47 45 }
691aa968
VM
46}
47
9462c471 48static void drop_index(git_repository *repo)
6fd195d7 49{
9462c471
VM
50 if (repo->_index != NULL) {
51 GIT_REFCOUNT_OWN(repo->_index, NULL);
52 git_index_free(repo->_index);
53 repo->_index = NULL;
54 }
e0011be3
VM
55}
56
9462c471 57void git_repository_free(git_repository *repo)
e0011be3 58{
9462c471
VM
59 if (repo == NULL)
60 return;
6fd195d7 61
9462c471
VM
62 git_cache_free(&repo->objects);
63 git_repository__refcache_free(&repo->references);
73b51450 64 git_attr_cache_flush(repo);
6fd195d7 65
9462c471
VM
66 git__free(repo->path_repository);
67 git__free(repo->workdir);
6fd195d7 68
9462c471
VM
69 drop_config(repo);
70 drop_index(repo);
71 drop_odb(repo);
72
73 git__free(repo);
6fd195d7
VM
74}
75
9462c471
VM
76/*
77 * Git repository open methods
78 *
79 * Open a repository object from its path
80 */
97769280 81static int quickcheck_repository_dir(git_buf *repository_path)
5ad739e8 82{
97769280 83 /* Check OBJECTS_DIR first, since it will generate the longest path name */
0534641d 84 if (git_path_contains_dir(repository_path, GIT_OBJECTS_DIR) < 0)
5ad739e8
VM
85 return GIT_ERROR;
86
97769280 87 /* Ensure HEAD file exists */
0534641d 88 if (git_path_contains_file(repository_path, GIT_HEAD_FILE) < 0)
5ad739e8
VM
89 return GIT_ERROR;
90
0534641d 91 if (git_path_contains_dir(repository_path, GIT_REFS_DIR) < 0)
5ad739e8
VM
92 return GIT_ERROR;
93
94 return GIT_SUCCESS;
95}
96
9462c471 97
51d00446 98static git_repository *repository_alloc(void)
3315782c 99{
81201a4c 100 int error;
101
3315782c
VM
102 git_repository *repo = git__malloc(sizeof(git_repository));
103 if (!repo)
104 return NULL;
105
106 memset(repo, 0x0, sizeof(git_repository));
107
81201a4c 108 error = git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
109 if (error < GIT_SUCCESS) {
3286c408 110 git__free(repo);
81201a4c 111 return NULL;
112 }
3315782c 113
6fd195d7
VM
114 return repo;
115}
116
9462c471 117static int load_config_data(git_repository *repo)
ec3c7a16 118{
9462c471
VM
119 int error, is_bare;
120 git_config *config;
ec3c7a16 121
9462c471
VM
122 error = git_repository_config__weakptr(&config, repo);
123 if (error < GIT_SUCCESS)
124 return error;
ec3c7a16 125
9462c471
VM
126 error = git_config_get_bool(config, "core.bare", &is_bare);
127 if (error == GIT_SUCCESS)
128 repo->is_bare = is_bare;
ec3c7a16 129
c94785a9
VM
130 /* TODO: what else can we load/cache here? */
131
9462c471
VM
132 return GIT_SUCCESS;
133}
ec3c7a16 134
9462c471
VM
135static int load_workdir(git_repository *repo)
136{
97769280
RB
137 int error;
138 git_buf workdir_buf = GIT_BUF_INIT;
ec3c7a16 139
97769280
RB
140 if (repo->is_bare)
141 return GIT_SUCCESS;
ec3c7a16 142
97769280
RB
143 git_path_dirname_r(&workdir_buf, repo->path_repository);
144 git_path_to_dir(&workdir_buf);
e0011be3 145
97769280
RB
146 if ((error = git_buf_lasterror(&workdir_buf)) == GIT_SUCCESS)
147 repo->workdir = git_buf_detach(&workdir_buf);
ec3c7a16 148
97769280
RB
149 git_buf_free(&workdir_buf);
150
151 return error;
ec3c7a16
VM
152}
153
9462c471 154int git_repository_open(git_repository **repo_out, const char *path)
691aa968 155{
691aa968 156 int error = GIT_SUCCESS;
97769280 157 git_buf path_buf = GIT_BUF_INIT;
9462c471
VM
158 git_repository *repo = NULL;
159
97769280 160 error = git_path_prettify_dir(&path_buf, path, NULL);
9462c471 161 if (error < GIT_SUCCESS)
97769280 162 goto cleanup;
9462c471
VM
163
164 /**
165 * Check if the path we've been given is actually the path
166 * of the working dir, by testing if it contains a `.git`
167 * folder inside of it.
168 */
0534641d
RB
169 if (git_path_contains_dir(&path_buf, GIT_DIR) == GIT_SUCCESS)
170 git_buf_joinpath(&path_buf, path_buf.ptr, GIT_DIR);
9462c471 171
97769280
RB
172 if (quickcheck_repository_dir(&path_buf) < GIT_SUCCESS) {
173 error = git__throw(GIT_ENOTAREPO,
0b44c065 174 "The given path (%s) is not a valid Git repository", git_buf_cstr(&path_buf));
97769280
RB
175 goto cleanup;
176 }
691aa968 177
e52ed7a5 178 repo = repository_alloc();
97769280
RB
179 if (repo == NULL) {
180 error = GIT_ENOMEM;
181 goto cleanup;
182 }
691aa968 183
97769280 184 repo->path_repository = git_buf_detach(&path_buf);
9462c471 185 if (repo->path_repository == NULL) {
97769280
RB
186 error = GIT_ENOMEM;
187 goto cleanup;
9462c471 188 }
691aa968 189
9462c471 190 error = load_config_data(repo);
97769280
RB
191 if (error < GIT_SUCCESS)
192 goto cleanup;
691aa968 193
9462c471 194 error = load_workdir(repo);
97769280
RB
195 if (error < GIT_SUCCESS)
196 goto cleanup;
691aa968
VM
197
198 *repo_out = repo;
199 return GIT_SUCCESS;
97769280
RB
200
201 cleanup:
202 git_repository_free(repo);
203 git_buf_free(&path_buf);
204 return error;
691aa968
VM
205}
206
9462c471 207static int load_config(
07ff8817
VM
208 git_config **out,
209 git_repository *repo,
40fe5fbe 210 const char *global_config_path,
07ff8817 211 const char *system_config_path)
b22d1479 212{
97769280 213 git_buf config_path = GIT_BUF_INIT;
07ff8817 214 int error;
9462c471 215 git_config *cfg = NULL;
b22d1479 216
9462c471 217 assert(repo && out);
07ff8817 218
9462c471 219 error = git_config_new(&cfg);
b22d1479 220 if (error < GIT_SUCCESS)
07ff8817 221 return error;
b22d1479 222
97769280
RB
223 error = git_buf_joinpath(&config_path, repo->path_repository,
224 GIT_CONFIG_FILENAME_INREPO);
225 if (error < GIT_SUCCESS)
226 goto cleanup;
227
228 error = git_config_add_file_ondisk(cfg, config_path.ptr, 3);
229 git_buf_free(&config_path); /* done with config_path now */
07ff8817 230 if (error < GIT_SUCCESS)
b22d1479 231 goto cleanup;
b22d1479 232
40fe5fbe 233 if (global_config_path != NULL) {
9462c471 234 error = git_config_add_file_ondisk(cfg, global_config_path, 2);
40fe5fbe
CMN
235 if (error < GIT_SUCCESS)
236 goto cleanup;
b22d1479
CMN
237 }
238
07ff8817 239 if (system_config_path != NULL) {
9462c471 240 error = git_config_add_file_ondisk(cfg, system_config_path, 1);
07ff8817
VM
241 if (error < GIT_SUCCESS)
242 goto cleanup;
9ba9e513
CMN
243 }
244
9462c471 245 *out = cfg;
07ff8817 246 return GIT_SUCCESS;
b22d1479
CMN
247
248cleanup:
9462c471
VM
249 git_config_free(cfg);
250 *out = NULL;
b22d1479
CMN
251 return error;
252}
253
9462c471 254int git_repository_config__weakptr(git_config **out, git_repository *repo)
40fe5fbe 255{
9462c471
VM
256 if (repo->_config == NULL) {
257 int error;
97769280 258 git_buf global_buf = GIT_BUF_INIT, system_buf = GIT_BUF_INIT;
9462c471
VM
259
260 const char *global_config_path = NULL;
261 const char *system_config_path = NULL;
40fe5fbe 262
97769280
RB
263 if (git_config_find_global_r(&global_buf) == GIT_SUCCESS)
264 global_config_path = global_buf.ptr;
40fe5fbe 265
97769280
RB
266 if (git_config_find_system_r(&system_buf) == GIT_SUCCESS)
267 system_config_path = system_buf.ptr;
40fe5fbe 268
9462c471 269 error = load_config(&repo->_config, repo, global_config_path, system_config_path);
97769280
RB
270
271 git_buf_free(&global_buf);
272 git_buf_free(&system_buf);
273
9462c471
VM
274 if (error < GIT_SUCCESS)
275 return error;
276
277 GIT_REFCOUNT_OWN(repo->_config, repo);
278 }
40fe5fbe 279
9462c471
VM
280 *out = repo->_config;
281 return GIT_SUCCESS;
40fe5fbe
CMN
282}
283
9462c471 284int git_repository_config(git_config **out, git_repository *repo)
fd0574e5 285{
9462c471 286 int error = git_repository_config__weakptr(out, repo);
fd0574e5 287
9462c471
VM
288 if (error == GIT_SUCCESS) {
289 GIT_REFCOUNT_INC(*out);
290 }
fd0574e5 291
9462c471
VM
292 return error;
293}
294
295void git_repository_set_config(git_repository *repo, git_config *config)
296{
297 assert(repo && config);
298
299 drop_config(repo);
300
301 repo->_config = config;
302 GIT_REFCOUNT_OWN(repo->_config, repo);
303}
304
305int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
306{
307 assert(repo && out);
308
309 if (repo->_odb == NULL) {
310 int error;
97769280 311 git_buf odb_path = GIT_BUF_INIT;
9462c471 312
97769280
RB
313 error = git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR);
314 if (error < GIT_SUCCESS)
315 return error;
9462c471 316
97769280
RB
317 error = git_odb_open(&repo->_odb, odb_path.ptr);
318 git_buf_free(&odb_path); /* done with path */
9462c471
VM
319 if (error < GIT_SUCCESS)
320 return error;
321
322 GIT_REFCOUNT_OWN(repo->_odb, repo);
323 }
fd0574e5 324
9462c471 325 *out = repo->_odb;
fd0574e5
RG
326 return GIT_SUCCESS;
327}
328
9462c471 329int git_repository_odb(git_odb **out, git_repository *repo)
6fd195d7 330{
9462c471 331 int error = git_repository_odb__weakptr(out, repo);
1795f879 332
9462c471
VM
333 if (error == GIT_SUCCESS) {
334 GIT_REFCOUNT_INC(*out);
335 }
6fd195d7 336
9462c471
VM
337 return error;
338}
6fd195d7 339
9462c471
VM
340void git_repository_set_odb(git_repository *repo, git_odb *odb)
341{
342 assert(repo && odb);
3315782c 343
9462c471 344 drop_odb(repo);
1795f879 345
9462c471
VM
346 repo->_odb = odb;
347 GIT_REFCOUNT_OWN(repo->_odb, repo);
348}
349
350int git_repository_index__weakptr(git_index **out, git_repository *repo)
351{
352 assert(out && repo);
353
9462c471
VM
354 if (repo->_index == NULL) {
355 int error;
97769280 356 git_buf index_path = GIT_BUF_INIT;
9462c471 357
97769280
RB
358 error = git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE);
359 if (error < GIT_SUCCESS)
360 return error;
9462c471 361
97769280
RB
362 error = git_index_open(&repo->_index, index_path.ptr);
363 git_buf_free(&index_path); /* done with path */
9462c471
VM
364 if (error < GIT_SUCCESS)
365 return error;
366
367 GIT_REFCOUNT_OWN(repo->_index, repo);
368 }
369
9462c471 370 *out = repo->_index;
1795f879 371 return GIT_SUCCESS;
9462c471 372}
1795f879 373
9462c471
VM
374int git_repository_index(git_index **out, git_repository *repo)
375{
376 int error = git_repository_index__weakptr(out, repo);
377
378 if (error == GIT_SUCCESS) {
379 GIT_REFCOUNT_INC(*out);
380 }
381
382 return error;
3315782c
VM
383}
384
9462c471
VM
385void git_repository_set_index(git_repository *repo, git_index *index)
386{
387 assert(repo && index);
388
389 drop_index(repo);
390
391 repo->_index = index;
392 GIT_REFCOUNT_OWN(repo->_index, repo);
393}
394
395
5ec05d07 396static int retrieve_device(dev_t *device_out, const char *path)
f2e6b877
RG
397{
398 struct stat path_info;
399
400 assert(device_out);
401
19ac1ed7 402 if (p_lstat(path, &path_info))
f2e6b877
RG
403 return git__throw(GIT_EOSERR, "Failed to get file informations: %s", path);
404
405 *device_out = path_info.st_dev;
406
407 return GIT_SUCCESS;
408}
409
97769280
RB
410/*
411 * This function returns furthest offset into path where a ceiling dir
412 * is found, so we can stop processing the path at that point.
413 *
414 * Note: converting this to use git_bufs instead of GIT_PATH_MAX buffers on
415 * the stack could remove directories name limits, but at the cost of doing
416 * repeated malloc/frees inside the loop below, so let's not do it now.
417 */
418static int retrieve_ceiling_directories_offset(
419 const char *path,
420 const char *ceiling_directories)
f2e6b877
RG
421{
422 char buf[GIT_PATH_MAX + 1];
423 char buf2[GIT_PATH_MAX + 1];
424 const char *ceil, *sep;
425 int len, max_len = -1;
426 int min_len;
427
428 assert(path);
429
5ad739e8 430 min_len = git_path_root(path) + 1;
f2e6b877
RG
431
432 if (ceiling_directories == NULL || min_len == 0)
433 return min_len;
434
435 for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) {
436 for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);
437 len = sep - ceil;
438
97769280 439 if (len == 0 || len >= (int)sizeof(buf) || git_path_root(ceil) == -1)
f2e6b877
RG
440 continue;
441
442 strncpy(buf, ceil, len);
443 buf[len] = '\0';
444
5ad739e8 445 if (p_realpath(buf, buf2) == NULL)
f2e6b877
RG
446 continue;
447
448 len = strlen(buf2);
449 if (len > 0 && buf2[len-1] == '/')
450 buf[--len] = '\0';
451
452 if (!strncmp(path, buf2, len) &&
453 path[len] == '/' &&
454 len > max_len)
455 {
456 max_len = len;
457 }
458 }
459
460 return max_len <= min_len ? min_len : max_len;
461}
462
97769280
RB
463/*
464 * Read the contents of `file_path` and set `path_out` to the repo dir that
465 * it points to. Before calling, set `path_out` to the base directory that
466 * should be used if the contents of `file_path` are a relative path.
467 */
468static int read_gitfile(git_buf *path_out, const char *file_path, const char *base_path)
6a01b6bd 469{
13224ea4 470 git_buf file = GIT_BUF_INIT;
6f1d23b2 471 int error;
6a01b6bd 472
97769280 473 assert(path_out && file_path);
6a01b6bd 474
f79026b4 475 error = git_futils_readbuffer(&file, file_path);
6a01b6bd
RG
476 if (error < GIT_SUCCESS)
477 return error;
478
13224ea4
VM
479 if (git__prefixcmp((char *)file.ptr, GIT_FILE_CONTENT_PREFIX)) {
480 git_buf_free(&file);
6a01b6bd
RG
481 return git__throw(GIT_ENOTFOUND, "Invalid gitfile format `%s`", file_path);
482 }
483
13224ea4 484 git_buf_rtrim(&file);
6a01b6bd 485
13224ea4
VM
486 if (strlen(GIT_FILE_CONTENT_PREFIX) == file.size) {
487 git_buf_free(&file);
6a01b6bd
RG
488 return git__throw(GIT_ENOTFOUND, "No path in git file `%s`", file_path);
489 }
490
97769280 491 error = git_path_prettify_dir(path_out,
13224ea4 492 ((char *)file.ptr) + strlen(GIT_FILE_CONTENT_PREFIX), base_path);
97769280 493
13224ea4 494 git_buf_free(&file);
6a01b6bd 495
1744fafe 496 if (error == GIT_SUCCESS && git_path_exists(path_out->ptr) == 0)
5ad739e8
VM
497 return GIT_SUCCESS;
498
97769280 499 return git__throw(GIT_EOBJCORRUPTED, "The `.git` file points to a nonexistent path");
6a01b6bd
RG
500}
501
9462c471
VM
502int git_repository_discover(
503 char *repository_path,
504 size_t size,
505 const char *start_path,
506 int across_fs,
507 const char *ceiling_dirs)
fd0574e5 508{
fd0574e5 509 int error, ceiling_offset;
97769280
RB
510 git_buf bare_path = GIT_BUF_INIT;
511 git_buf normal_path = GIT_BUF_INIT;
512 git_buf *found_path = NULL;
393a9f9e 513 dev_t current_device = 0;
fd0574e5
RG
514
515 assert(start_path && repository_path);
fd0574e5 516
97769280
RB
517 *repository_path = '\0';
518
519 error = git_path_prettify_dir(&bare_path, start_path, NULL);
fd0574e5 520 if (error < GIT_SUCCESS)
97769280 521 goto cleanup;
fd0574e5
RG
522
523 if (!across_fs) {
97769280 524 error = retrieve_device(&current_device, bare_path.ptr);
fd0574e5 525 if (error < GIT_SUCCESS)
97769280 526 goto cleanup;
fd0574e5
RG
527 }
528
97769280 529 ceiling_offset = retrieve_ceiling_directories_offset(bare_path.ptr, ceiling_dirs);
fd0574e5 530
5ad739e8 531 while(1) {
97769280
RB
532 error = git_buf_joinpath(&normal_path, bare_path.ptr, DOT_GIT);
533 if (error < GIT_SUCCESS)
534 break;
535
5ad739e8
VM
536 /**
537 * If the `.git` file is regular instead of
538 * a directory, it should contain the path of the actual git repository
539 */
1744fafe 540 if (git_path_isfile(normal_path.ptr) == GIT_SUCCESS) {
97769280 541 git_buf gitfile_path = GIT_BUF_INIT;
fd0574e5 542
97769280 543 error = read_gitfile(&gitfile_path, normal_path.ptr, bare_path.ptr);
fd0574e5 544 if (error < GIT_SUCCESS)
97769280
RB
545 git__rethrow(error, "Unable to read git file `%s`", normal_path.ptr);
546 else if ((error = quickcheck_repository_dir(&gitfile_path)) < GIT_SUCCESS)
547 git__throw(GIT_ENOTFOUND,
548 "The `.git` file found at '%s' points "
549 "to a nonexistent git folder", normal_path.ptr);
550 else {
551 git_buf_swap(&normal_path, &gitfile_path);
552 found_path = &normal_path;
553 }
fd0574e5 554
97769280
RB
555 git_buf_free(&gitfile_path);
556 break;
fd0574e5
RG
557 }
558
5ad739e8
VM
559 /**
560 * If the `.git` file is a folder, we check inside of it
561 */
1744fafe 562 if (git_path_isdir(normal_path.ptr) == GIT_SUCCESS) {
97769280 563 error = quickcheck_repository_dir(&normal_path);
5ad739e8 564 if (error == GIT_SUCCESS) {
97769280 565 found_path = &normal_path;
5ad739e8
VM
566 break;
567 }
fd0574e5
RG
568 }
569
5ad739e8
VM
570 /**
571 * Otherwise, the repository may be bare, let's check
572 * the root anyway
573 */
97769280 574 error = quickcheck_repository_dir(&bare_path);
fd0574e5 575 if (error == GIT_SUCCESS) {
97769280 576 found_path = &bare_path;
fd0574e5
RG
577 break;
578 }
579
97769280
RB
580 /**
581 * If we didn't find it, walk up the tree
582 */
583 error = git_path_dirname_r(&normal_path, bare_path.ptr);
584 if (error < GIT_SUCCESS) {
585 git__rethrow(GIT_EOSERR, "Failed to dirname '%s'", bare_path.ptr);
586 break;
587 }
588
589 git_buf_swap(&bare_path, &normal_path);
fd0574e5
RG
590
591 if (!across_fs) {
592 dev_t new_device;
97769280 593 error = retrieve_device(&new_device, bare_path.ptr);
fd0574e5 594
5ad739e8 595 if (error < GIT_SUCCESS || current_device != new_device) {
97769280 596 error = git__throw(GIT_ENOTAREPO,
9462c471 597 "Not a git repository (or any parent up to mount parent %s)\n"
97769280
RB
598 "Stopping at filesystem boundary.", normal_path.ptr);
599 break;
fd0574e5
RG
600 }
601 current_device = new_device;
602 }
603
97769280
RB
604 /* nothing has been found, lets try the parent directory
605 * but stop if we hit one of the ceiling directories
606 */
607 if (bare_path.ptr[ceiling_offset] == '\0') {
608 error = git__throw(GIT_ENOTAREPO,
9462c471 609 "Not a git repository (or any of the parent directories): %s", start_path);
97769280 610 break;
9d9bab5c 611 }
fd0574e5
RG
612 }
613
97769280
RB
614 assert(found_path || error != GIT_SUCCESS);
615
616 if (found_path) {
617 if ((error = git_path_to_dir(found_path)) < GIT_SUCCESS)
618 git__rethrow(error, "Could not convert git repository to directory");
619 else if (size < (size_t)(found_path->size + 1))
620 error = git__throw(GIT_ESHORTBUFFER,
621 "The repository buffer is not long enough to "
622 "handle the repository path `%s`", found_path->ptr);
623 else
624 git_buf_copy_cstr(repository_path, size, found_path);
fd0574e5
RG
625 }
626
97769280
RB
627cleanup:
628 git_buf_free(&bare_path);
629 git_buf_free(&normal_path);
630 return error;
fd0574e5
RG
631}
632
5663e61a 633static int check_repositoryformatversion(git_repository *repo)
40c44d2f 634{
5663e61a 635 git_config *config;
636 int version, error = GIT_SUCCESS;
637
638 if ((error = git_repository_config(&config, repo)) < GIT_SUCCESS)
639 return git__throw(error, "Failed to open config file.");
640
641 error = git_config_get_int32(config, GIT_CONFIG_CORE_REPOSITORYFORMATVERSION, &version);
642
643 if (GIT_REPOSITORYFORMATVERSION < version)
644 error = git__throw(GIT_ERROR, "Unsupported git repository version (Expected version <= %d, found %d).", GIT_REPOSITORYFORMATVERSION, version);
645
646 git_config_free(config);
647
648 return error;
649}
650
651static int repo_init_reinit(git_repository **repo_out, const char *repository_path, int is_bare)
652{
653 int error;
654 git_repository *repo = NULL;
655
656 if ((error = git_repository_open(&repo, repository_path)) < GIT_SUCCESS)
657 goto error;
658
659 if ((error = check_repositoryformatversion(repo)) < GIT_SUCCESS)
660 goto error;
661
662 /* TODO: reinitialize the templates */
663
664 *repo_out = repo;
665
666 return GIT_SUCCESS;
667
668error:
669 git_repository_free(repo);
670
671 return git__rethrow(error,
672 "Failed to reinitialize the %srepository at '%s'. ",
9462c471 673 is_bare ? "bare " : "", repository_path);
4b8e27c8 674}
675
9462c471 676static int repo_init_createhead(const char *git_dir)
e1f8cad0 677{
97769280
RB
678 int error;
679 git_buf ref_path = GIT_BUF_INIT;
9462c471
VM
680 git_filebuf ref = GIT_FILEBUF_INIT;
681
97769280
RB
682 if (!(error = git_buf_joinpath(&ref_path, git_dir, GIT_HEAD_FILE)) &&
683 !(error = git_filebuf_open(&ref, ref_path.ptr, 0)) &&
684 !(error = git_filebuf_printf(&ref, "ref: refs/heads/master\n")))
685 error = git_filebuf_commit(&ref, GIT_REFS_FILE_MODE);
9462c471 686
97769280
RB
687 git_buf_free(&ref_path);
688 return error;
9462c471
VM
689}
690
691static int repo_init_config(const char *git_dir, int is_bare)
692{
97769280
RB
693 git_buf cfg_path = GIT_BUF_INIT;
694 git_config *config = NULL;
9462c471
VM
695 int error = GIT_SUCCESS;
696
697#define SET_REPO_CONFIG(type, name, val) {\
698 error = git_config_set_##type(config, name, val);\
699 if (error < GIT_SUCCESS)\
700 goto cleanup;\
701}
702
97769280
RB
703 error = git_buf_joinpath(&cfg_path, git_dir, GIT_CONFIG_FILENAME_INREPO);
704 if (error < GIT_SUCCESS)
705 goto cleanup;
9462c471 706
97769280 707 error = git_config_open_ondisk(&config, cfg_path.ptr);
9462c471 708 if (error < GIT_SUCCESS)
97769280 709 goto cleanup;
9462c471
VM
710
711 SET_REPO_CONFIG(bool, "core.bare", is_bare);
5663e61a 712 SET_REPO_CONFIG(int32, GIT_CONFIG_CORE_REPOSITORYFORMATVERSION, GIT_REPOSITORYFORMATVERSION);
9462c471
VM
713 /* TODO: what other defaults? */
714
715cleanup:
97769280 716 git_buf_free(&cfg_path);
9462c471 717 git_config_free(config);
75abd2b9 718 return error;
d2d6912e 719}
e1f8cad0 720
ed72182b 721static int repo_init_structure(const char *git_dir, int is_bare)
4b8e27c8 722{
97769280
RB
723 int error, i;
724 struct { const char *dir; mode_t mode; } dirs[] = {
725 { GIT_OBJECTS_INFO_DIR, GIT_OBJECT_DIR_MODE }, /* '/objects/info/' */
726 { GIT_OBJECTS_PACK_DIR, GIT_OBJECT_DIR_MODE }, /* '/objects/pack/' */
727 { GIT_REFS_HEADS_DIR, GIT_REFS_DIR_MODE }, /* '/refs/heads/' */
728 { GIT_REFS_TAGS_DIR, GIT_REFS_DIR_MODE }, /* '/refs/tags/' */
729 { NULL, 0 }
730 };
731
732 /* Make the base directory */
733 error = git_futils_mkdir_r(git_dir, NULL, is_bare ?
734 GIT_BARE_DIR_MODE : GIT_DIR_MODE);
735 if (error < GIT_SUCCESS)
736 return git__rethrow(error, "Failed to initialize repository structure. Could not mkdir");
a67a096a 737
6ac91dfe 738 /* Hides the ".git" directory */
ed72182b 739 if (!is_bare) {
17837602 740#ifdef GIT_WIN32
f79026b4 741 error = p_hide_directory__w32(git_dir);
6ac91dfe 742 if (error < GIT_SUCCESS)
743 return git__rethrow(error, "Failed to initialize repository structure");
6ac91dfe 744#endif
17837602 745 }
6ac91dfe 746
97769280
RB
747 /* Make subdirectories as needed */
748 for (i = 0; dirs[i].dir != NULL; ++i) {
749 error = git_futils_mkdir_r(dirs[i].dir, git_dir, dirs[i].mode);
750 if (error < GIT_SUCCESS)
751 return git__rethrow(error,
752 "Failed to create repository folder `%s`", dirs[i].dir);
753 }
1c2c7c0d 754
40c44d2f 755 /* TODO: what's left? templates? */
4b8e27c8 756
97769280 757 return error;
4b8e27c8 758}
759
40c44d2f 760int git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare)
4b8e27c8 761{
4b8e27c8 762 int error = GIT_SUCCESS;
e0011be3 763 git_repository *repo = NULL;
97769280 764 git_buf repository_path = GIT_BUF_INIT;
932d1baf 765
4b8e27c8 766 assert(repo_out && path);
767
97769280
RB
768 error = git_buf_joinpath(&repository_path, path, is_bare ? "" : GIT_DIR);
769 if (error < GIT_SUCCESS)
770 return error;
4b8e27c8 771
1744fafe 772 if (git_path_isdir(repository_path.ptr) == GIT_SUCCESS) {
97769280 773 if (quickcheck_repository_dir(&repository_path) == GIT_SUCCESS) {
5663e61a 774 error = repo_init_reinit(repo_out, repository_path.ptr, is_bare);
97769280
RB
775 git_buf_free(&repository_path);
776 return error;
777 }
1bc83ff1 778 }
d2d6912e 779
97769280
RB
780 if (!(error = repo_init_structure(repository_path.ptr, is_bare)) &&
781 !(error = repo_init_config(repository_path.ptr, is_bare)) &&
782 !(error = repo_init_createhead(repository_path.ptr)))
783 error = git_repository_open(repo_out, repository_path.ptr);
784 else
785 git_repository_free(repo);
d2d6912e 786
97769280 787 git_buf_free(&repository_path);
e0011be3 788
97769280
RB
789 if (error != GIT_SUCCESS)
790 git__rethrow(error, "Failed to (re)init the repository `%s`", path);
4b8e27c8 791
97769280 792 return error;
40c44d2f 793}
35502d2e 794
c682886e 795int git_repository_head_detached(git_repository *repo)
35502d2e
CMN
796{
797 git_reference *ref;
798 int error;
9462c471 799 size_t _size;
35502d2e 800 git_otype type;
9462c471
VM
801 git_odb *odb = NULL;
802
803 error = git_repository_odb__weakptr(&odb, repo);
804 if (error < GIT_SUCCESS)
805 return error;
35502d2e
CMN
806
807 error = git_reference_lookup(&ref, repo, GIT_HEAD_FILE);
808 if (error < GIT_SUCCESS)
809 return error;
810
75abd2b9
MS
811 if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
812 git_reference_free(ref);
35502d2e 813 return 0;
75abd2b9 814 }
35502d2e 815
9462c471 816 error = git_odb_read_header(&_size, &type, odb, git_reference_oid(ref));
75abd2b9
MS
817
818 git_reference_free(ref);
819
35502d2e
CMN
820 if (error < GIT_SUCCESS)
821 return error;
822
823 if (type != GIT_OBJ_COMMIT)
824 return git__throw(GIT_EOBJCORRUPTED, "HEAD is not a commit");
825
826 return 1;
827}
828
3601c4bf 829int git_repository_head(git_reference **head_out, git_repository *repo)
35502d2e 830{
75abd2b9 831 git_reference *ref, *resolved_ref;
35502d2e
CMN
832 int error;
833
3601c4bf 834 *head_out = NULL;
835
35502d2e
CMN
836 error = git_reference_lookup(&ref, repo, GIT_HEAD_FILE);
837 if (error < GIT_SUCCESS)
3601c4bf 838 return git__rethrow(GIT_ENOTAREPO, "Failed to locate the HEAD");
35502d2e 839
75abd2b9
MS
840 error = git_reference_resolve(&resolved_ref, ref);
841 if (error < GIT_SUCCESS) {
842 git_reference_free(ref);
3601c4bf 843 return git__rethrow(error, "Failed to resolve the HEAD");
75abd2b9 844 }
3601c4bf 845
75abd2b9
MS
846 git_reference_free(ref);
847
848 *head_out = resolved_ref;
3601c4bf 849 return GIT_SUCCESS;
850}
851
852int git_repository_head_orphan(git_repository *repo)
853{
854 git_reference *ref;
855 int error;
856
857 error = git_repository_head(&ref, repo);
35502d2e 858
75abd2b9
MS
859 if (error == GIT_SUCCESS)
860 git_reference_free(ref);
861
35502d2e
CMN
862 return error == GIT_ENOTFOUND ? 1 : error;
863}
e0011be3 864
41233c40
VM
865int git_repository_is_empty(git_repository *repo)
866{
d4a0b124 867 git_reference *head = NULL, *branch = NULL;
41233c40
VM
868 int error;
869
870 error = git_reference_lookup(&head, repo, "HEAD");
871 if (error < GIT_SUCCESS)
0f489fb2 872 return git__throw(error, "Corrupted repository. HEAD does not exist");
41233c40 873
75abd2b9
MS
874 if (git_reference_type(head) != GIT_REF_SYMBOLIC) {
875 git_reference_free(head);
0f489fb2 876 return 0;
75abd2b9 877 }
0f489fb2 878
75abd2b9
MS
879 if (strcmp(git_reference_target(head), "refs/heads/master") != 0) {
880 git_reference_free(head);
0f489fb2 881 return 0;
75abd2b9 882 }
41233c40 883
0f489fb2 884 error = git_reference_resolve(&branch, head);
75abd2b9
MS
885
886 git_reference_free(head);
887 git_reference_free(branch);
888
0f489fb2 889 return error == GIT_ENOTFOUND ? 1 : error;
41233c40
VM
890}
891
9462c471 892const char *git_repository_path(git_repository *repo)
4a34b3a9 893{
894 assert(repo);
9462c471
VM
895 return repo->path_repository;
896}
4a34b3a9 897
9462c471
VM
898const char *git_repository_workdir(git_repository *repo)
899{
900 assert(repo);
602ee38b 901
9462c471
VM
902 if (repo->is_bare)
903 return NULL;
602ee38b 904
9462c471
VM
905 return repo->workdir;
906}
602ee38b 907
9462c471
VM
908int git_repository_set_workdir(git_repository *repo, const char *workdir)
909{
910 assert(repo && workdir);
602ee38b 911
9462c471
VM
912 free(repo->workdir);
913
914 repo->workdir = git__strdup(workdir);
915 if (repo->workdir == NULL)
916 return GIT_ENOMEM;
917
918 repo->is_bare = 0;
919 return GIT_SUCCESS;
4a34b3a9 920}
fa9bcd81 921
922int git_repository_is_bare(git_repository *repo)
923{
924 assert(repo);
925 return repo->is_bare;
926}