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