]> git.proxmox.com Git - libgit2.git/blame - src/repository.c
CMakefile: add -Wstrict-aliasing=2 and fix warnings
[libgit2.git] / src / repository.c
CommitLineData
3315782c
VM
1/*
2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
5 *
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
14 *
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
e802d8cc 25#include <stdarg.h>
3315782c 26
44908fe7 27#include "git2/object.h"
d12299fe 28
3315782c
VM
29#include "common.h"
30#include "repository.h"
31#include "commit.h"
32#include "tag.h"
237da401 33#include "blob.h"
6fd195d7 34#include "fileops.h"
b22d1479 35#include "config.h"
9282e921 36#include "refs.h"
37
f2d6a23a 38#define GIT_OBJECTS_INFO_DIR GIT_OBJECTS_DIR "info/"
39#define GIT_OBJECTS_PACK_DIR GIT_OBJECTS_DIR "pack/"
40c44d2f 40
6a01b6bd 41#define GIT_FILE_CONTENT_PREFIX "gitdir: "
6a01b6bd 42
28990938 43#define GIT_BRANCH_MASTER "master"
44
e52ed7a5
VM
45/*
46 * Git repository open methods
47 *
48 * Open a repository object from its path
49 */
e0011be3
VM
50static int assign_repository_dirs(
51 git_repository *repo,
691aa968
VM
52 const char *git_dir,
53 const char *git_object_directory,
54 const char *git_index_file,
e0011be3 55 const char *git_work_tree)
691aa968
VM
56{
57 char path_aux[GIT_PATH_MAX];
eb2f3b47 58 int error = GIT_SUCCESS;
691aa968
VM
59
60 assert(repo);
61
eb2f3b47 62 if (git_dir == NULL)
4f664a1b 63 return git__throw(GIT_ENOTFOUND, "Failed to open repository. Git dir not found");
691aa968 64
eec3fe39 65 error = git_path_prettify_dir(path_aux, git_dir, NULL);
eb2f3b47 66 if (error < GIT_SUCCESS)
4f664a1b 67 return git__rethrow(error, "Failed to open repository");
691aa968 68
eb2f3b47 69 /* store GIT_DIR */
691aa968 70 repo->path_repository = git__strdup(path_aux);
8212e2d7
VM
71 if (repo->path_repository == NULL)
72 return GIT_ENOMEM;
691aa968 73
d2d6912e 74 /* path to GIT_OBJECT_DIRECTORY */
691aa968 75 if (git_object_directory == NULL)
f79026b4 76 git_path_join(path_aux, repo->path_repository, GIT_OBJECTS_DIR);
eb2f3b47 77 else {
eec3fe39 78 error = git_path_prettify_dir(path_aux, git_object_directory, NULL);
eb2f3b47 79 if (error < GIT_SUCCESS)
4f664a1b 80 return git__rethrow(error, "Failed to open repository");
eb2f3b47 81 }
691aa968 82
d2d6912e 83 /* Store GIT_OBJECT_DIRECTORY */
691aa968 84 repo->path_odb = git__strdup(path_aux);
8212e2d7
VM
85 if (repo->path_odb == NULL)
86 return GIT_ENOMEM;
691aa968 87
d2d6912e 88 /* path to GIT_WORK_TREE */
691aa968
VM
89 if (git_work_tree == NULL)
90 repo->is_bare = 1;
eb2f3b47 91 else {
eec3fe39 92 error = git_path_prettify_dir(path_aux, git_work_tree, NULL);
eb2f3b47 93 if (error < GIT_SUCCESS)
4f664a1b 94 return git__rethrow(error, "Failed to open repository");
d2d6912e 95
96 /* Store GIT_WORK_TREE */
eb2f3b47 97 repo->path_workdir = git__strdup(path_aux);
8212e2d7
VM
98 if (repo->path_workdir == NULL)
99 return GIT_ENOMEM;
d2d6912e 100
101 /* Path to GIT_INDEX_FILE */
102 if (git_index_file == NULL)
f79026b4 103 git_path_join(path_aux, repo->path_repository, GIT_INDEX_FILE);
d2d6912e 104 else {
eec3fe39 105 error = git_path_prettify(path_aux, git_index_file, NULL);
d2d6912e 106 if (error < GIT_SUCCESS)
4f664a1b 107 return git__rethrow(error, "Failed to open repository");
d2d6912e 108 }
109
d2d6912e 110 /* store GIT_INDEX_FILE */
111 repo->path_index = git__strdup(path_aux);
112 if (repo->path_index == NULL)
113 return GIT_ENOMEM;
eb2f3b47 114 }
932d1baf 115
691aa968
VM
116 return GIT_SUCCESS;
117}
118
e0011be3 119static int check_repository_dirs(git_repository *repo)
6fd195d7 120{
e0011be3 121 char path_aux[GIT_PATH_MAX];
f725931b 122
f79026b4 123 if (git_futils_isdir(repo->path_repository) < GIT_SUCCESS)
3abe3bba 124 return git__throw(GIT_ENOTAREPO, "`%s` is not a folder", repo->path_repository);
6fd195d7 125
e0011be3 126 /* Ensure GIT_OBJECT_DIRECTORY exists */
f79026b4 127 if (git_futils_isdir(repo->path_odb) < GIT_SUCCESS)
3abe3bba 128 return git__throw(GIT_ENOTAREPO, "`%s` does not exist", repo->path_odb);
e0011be3
VM
129
130 /* Ensure HEAD file exists */
f79026b4 131 git_path_join(path_aux, repo->path_repository, GIT_HEAD_FILE);
5ad739e8 132 if (git_futils_isfile(path_aux) < 0)
3abe3bba 133 return git__throw(GIT_ENOTAREPO, "HEAD file is missing");
e0011be3
VM
134
135 return GIT_SUCCESS;
136}
137
138static int guess_repository_dirs(git_repository *repo, const char *repository_path)
139{
140 char buffer[GIT_PATH_MAX];
141 const char *path_work_tree = NULL;
6fd195d7 142
d2d6912e 143 /* Git directory name */
f79026b4 144 if (git_path_basename_r(buffer, sizeof(buffer), repository_path) < 0)
3abe3bba 145 return git__throw(GIT_EINVALIDPATH, "Unable to parse folder name from `%s`", repository_path);
6fd195d7 146
e0011be3 147 if (strcmp(buffer, DOT_GIT) == 0) {
d2d6912e 148 /* Path to working dir */
f79026b4 149 if (git_path_dirname_r(buffer, sizeof(buffer), repository_path) < 0)
3abe3bba 150 return git__throw(GIT_EINVALIDPATH, "Unable to parse parent folder name from `%s`", repository_path);
e0011be3 151 path_work_tree = buffer;
6fd195d7
VM
152 }
153
e0011be3 154 return assign_repository_dirs(repo, repository_path, NULL, NULL, path_work_tree);
6fd195d7
VM
155}
156
5ad739e8
VM
157static int quickcheck_repository_dir(const char *repository_path)
158{
159 char path_aux[GIT_PATH_MAX];
160
161 /* Ensure HEAD file exists */
162 git_path_join(path_aux, repository_path, GIT_HEAD_FILE);
163 if (git_futils_isfile(path_aux) < 0)
164 return GIT_ERROR;
165
166 git_path_join(path_aux, repository_path, GIT_OBJECTS_DIR);
167 if (git_futils_isdir(path_aux) < 0)
168 return GIT_ERROR;
169
170 git_path_join(path_aux, repository_path, GIT_REFS_DIR);
171 if (git_futils_isdir(path_aux) < 0)
172 return GIT_ERROR;
173
174 return GIT_SUCCESS;
175}
176
e52ed7a5 177static git_repository *repository_alloc()
3315782c 178{
81201a4c 179 int error;
180
3315782c
VM
181 git_repository *repo = git__malloc(sizeof(git_repository));
182 if (!repo)
183 return NULL;
184
185 memset(repo, 0x0, sizeof(git_repository));
186
81201a4c 187 error = git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
188 if (error < GIT_SUCCESS) {
189 free(repo);
190 return NULL;
191 }
3315782c 192
2f8a8ab2 193 if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {
48c27f86
VM
194 free(repo);
195 return NULL;
196 }
197
6fd195d7
VM
198 return repo;
199}
200
ec3c7a16
VM
201static int init_odb(git_repository *repo)
202{
cf7dc39b 203 return git_odb_open(&repo->db, repo->path_odb);
ec3c7a16
VM
204}
205
206int git_repository_open3(git_repository **repo_out,
207 const char *git_dir,
208 git_odb *object_database,
209 const char *git_index_file,
210 const char *git_work_tree)
211{
212 git_repository *repo;
213 int error = GIT_SUCCESS;
214
215 assert(repo_out);
216
217 if (object_database == NULL)
3abe3bba 218 return git__throw(GIT_EINVALIDARGS, "Failed to open repository. `object_database` can't be null");
ec3c7a16
VM
219
220 repo = repository_alloc();
221 if (repo == NULL)
222 return GIT_ENOMEM;
223
932d1baf
KS
224 error = assign_repository_dirs(repo,
225 git_dir,
ec3c7a16
VM
226 NULL,
227 git_index_file,
e0011be3 228 git_work_tree);
ec3c7a16
VM
229
230 if (error < GIT_SUCCESS)
231 goto cleanup;
232
e0011be3
VM
233 error = check_repository_dirs(repo);
234 if (error < GIT_SUCCESS)
235 goto cleanup;
236
ec3c7a16
VM
237 repo->db = object_database;
238
239 *repo_out = repo;
240 return GIT_SUCCESS;
241
242cleanup:
243 git_repository_free(repo);
3abe3bba 244 return git__rethrow(error, "Failed to open repository");
ec3c7a16
VM
245}
246
247
691aa968
VM
248int git_repository_open2(git_repository **repo_out,
249 const char *git_dir,
250 const char *git_object_directory,
251 const char *git_index_file,
252 const char *git_work_tree)
253{
254 git_repository *repo;
255 int error = GIT_SUCCESS;
256
257 assert(repo_out);
258
e52ed7a5 259 repo = repository_alloc();
691aa968
VM
260 if (repo == NULL)
261 return GIT_ENOMEM;
262
e0011be3 263 error = assign_repository_dirs(repo,
932d1baf 264 git_dir,
691aa968
VM
265 git_object_directory,
266 git_index_file,
e0011be3
VM
267 git_work_tree);
268
269 if (error < GIT_SUCCESS)
270 goto cleanup;
691aa968 271
e0011be3 272 error = check_repository_dirs(repo);
6f02c3ba 273 if (error < GIT_SUCCESS)
691aa968
VM
274 goto cleanup;
275
ec3c7a16 276 error = init_odb(repo);
6f02c3ba 277 if (error < GIT_SUCCESS)
691aa968
VM
278 goto cleanup;
279
280 *repo_out = repo;
281 return GIT_SUCCESS;
282
283cleanup:
284 git_repository_free(repo);
3abe3bba 285 return git__rethrow(error, "Failed to open repository");
691aa968
VM
286}
287
07ff8817
VM
288int git_repository_config(
289 git_config **out,
290 git_repository *repo,
291 const char *user_config_path,
292 const char *system_config_path)
b22d1479 293{
07ff8817
VM
294 char config_path[GIT_PATH_MAX];
295 int error;
b22d1479 296
07ff8817
VM
297 assert(out && repo);
298
299 error = git_config_new(out);
b22d1479 300 if (error < GIT_SUCCESS)
07ff8817 301 return error;
b22d1479 302
f79026b4 303 git_path_join(config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO);
2a406ab5 304 error = git_config_add_file_ondisk(*out, config_path, 3);
07ff8817 305 if (error < GIT_SUCCESS)
b22d1479 306 goto cleanup;
b22d1479 307
07ff8817
VM
308 if (user_config_path != NULL) {
309 error = git_config_add_file_ondisk(*out, user_config_path, 2);
310 if (error < GIT_SUCCESS)
311 goto cleanup;
b22d1479
CMN
312 }
313
07ff8817 314 if (system_config_path != NULL) {
2a406ab5 315 error = git_config_add_file_ondisk(*out, system_config_path, 1);
07ff8817
VM
316 if (error < GIT_SUCCESS)
317 goto cleanup;
9ba9e513
CMN
318 }
319
44daec42 320 (*out)->repo = repo;
07ff8817 321 return GIT_SUCCESS;
b22d1479
CMN
322
323cleanup:
07ff8817 324 git_config_free(*out);
b22d1479
CMN
325 return error;
326}
327
fd0574e5
RG
328static int discover_repository_dirs(git_repository *repo, const char *path)
329{
330 int error;
331
332 error = guess_repository_dirs(repo, path);
333 if (error < GIT_SUCCESS)
334 return error;
335
336 error = check_repository_dirs(repo);
337 if (error < GIT_SUCCESS)
338 return error;
339
340 return GIT_SUCCESS;
341}
342
e0011be3 343int git_repository_open(git_repository **repo_out, const char *path)
6fd195d7
VM
344{
345 git_repository *repo;
1795f879
VM
346 int error = GIT_SUCCESS;
347
348 assert(repo_out && path);
6fd195d7 349
e52ed7a5 350 repo = repository_alloc();
6fd195d7 351 if (repo == NULL)
1795f879 352 return GIT_ENOMEM;
6fd195d7 353
fd0574e5 354 error = discover_repository_dirs(repo, path);
6f02c3ba 355 if (error < GIT_SUCCESS)
1795f879 356 goto cleanup;
3315782c 357
ec3c7a16 358 error = init_odb(repo);
6f02c3ba 359 if (error < GIT_SUCCESS)
1795f879
VM
360 goto cleanup;
361
362 *repo_out = repo;
363 return GIT_SUCCESS;
364
365cleanup:
366 git_repository_free(repo);
3abe3bba 367 return git__rethrow(error, "Failed to open repository");
3315782c
VM
368}
369
5ec05d07 370static int retrieve_device(dev_t *device_out, const char *path)
f2e6b877
RG
371{
372 struct stat path_info;
373
374 assert(device_out);
375
19ac1ed7 376 if (p_lstat(path, &path_info))
f2e6b877
RG
377 return git__throw(GIT_EOSERR, "Failed to get file informations: %s", path);
378
379 *device_out = path_info.st_dev;
380
381 return GIT_SUCCESS;
382}
383
384static int retrieve_ceiling_directories_offset(const char *path, const char *ceiling_directories)
385{
386 char buf[GIT_PATH_MAX + 1];
387 char buf2[GIT_PATH_MAX + 1];
388 const char *ceil, *sep;
389 int len, max_len = -1;
390 int min_len;
391
392 assert(path);
393
5ad739e8 394 min_len = git_path_root(path) + 1;
f2e6b877
RG
395
396 if (ceiling_directories == NULL || min_len == 0)
397 return min_len;
398
399 for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) {
400 for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);
401 len = sep - ceil;
402
5ad739e8 403 if (len == 0 || len > GIT_PATH_MAX || git_path_root(ceil) == -1)
f2e6b877
RG
404 continue;
405
406 strncpy(buf, ceil, len);
407 buf[len] = '\0';
408
5ad739e8 409 if (p_realpath(buf, buf2) == NULL)
f2e6b877
RG
410 continue;
411
412 len = strlen(buf2);
413 if (len > 0 && buf2[len-1] == '/')
414 buf[--len] = '\0';
415
416 if (!strncmp(path, buf2, len) &&
417 path[len] == '/' &&
418 len > max_len)
419 {
420 max_len = len;
421 }
422 }
423
424 return max_len <= min_len ? min_len : max_len;
425}
426
5ad739e8 427static int read_gitfile(char *path_out, const char *file_path, const char *base_path)
6a01b6bd 428{
f79026b4 429 git_fbuffer file;
6f1d23b2
VM
430 int error;
431 size_t end_offset;
6a01b6bd
RG
432 char *data;
433
7a44cc41 434 assert(path_out && file_path && base_path);
6a01b6bd 435
f79026b4 436 error = git_futils_readbuffer(&file, file_path);
6a01b6bd
RG
437
438 if (error < GIT_SUCCESS)
439 return error;
440
441 data = (char*)(file.data);
442
443 if (git__prefixcmp(data, GIT_FILE_CONTENT_PREFIX)) {
f79026b4 444 git_futils_freebuffer(&file);
6a01b6bd
RG
445 return git__throw(GIT_ENOTFOUND, "Invalid gitfile format `%s`", file_path);
446 }
447
448 end_offset = strlen(data) - 1;
449
8b05e780
RG
450 for (;data[end_offset] == '\r' || data[end_offset] == '\n'; --end_offset);
451 data[end_offset + 1] = '\0';
6a01b6bd 452
932669b8 453 if (strlen(GIT_FILE_CONTENT_PREFIX) == end_offset + 1) {
f79026b4 454 git_futils_freebuffer(&file);
6a01b6bd
RG
455 return git__throw(GIT_ENOTFOUND, "No path in git file `%s`", file_path);
456 }
457
932669b8 458 data = data + strlen(GIT_FILE_CONTENT_PREFIX);
5ad739e8 459 error = git_path_prettify_dir(path_out, data, base_path);
f79026b4 460 git_futils_freebuffer(&file);
6a01b6bd 461
5ad739e8
VM
462 if (error == 0 && git_futils_exists(path_out) == 0)
463 return GIT_SUCCESS;
464
465 return git__throw(GIT_EOBJCORRUPTED, "The `.git` file points to an inexisting path");
6a01b6bd
RG
466}
467
222cf1d4
RG
468static void git_repository__free_dirs(git_repository *repo)
469{
470 free(repo->path_workdir);
471 repo->path_workdir = NULL;
472 free(repo->path_index);
473 repo->path_index = NULL;
474 free(repo->path_repository);
475 repo->path_repository = NULL;
476 free(repo->path_odb);
477 repo->path_odb = NULL;
478}
479
584f49a5
VM
480void git_repository_free(git_repository *repo)
481{
584f49a5
VM
482 if (repo == NULL)
483 return;
6fd195d7 484
72a3fe42
VM
485 git_cache_free(&repo->objects);
486 git_repository__refcache_free(&repo->references);
222cf1d4 487 git_repository__free_dirs(repo);
6b2a1941 488
6b2a1941
VM
489 if (repo->db != NULL)
490 git_odb_close(repo->db);
491
6b2a1941 492 free(repo);
3315782c
VM
493}
494
fd0574e5
RG
495int git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs)
496{
fd0574e5
RG
497 int error, ceiling_offset;
498 char bare_path[GIT_PATH_MAX];
499 char normal_path[GIT_PATH_MAX];
500 char *found_path;
393a9f9e 501 dev_t current_device = 0;
fd0574e5
RG
502
503 assert(start_path && repository_path);
fd0574e5 504
5ad739e8 505 error = git_path_prettify_dir(bare_path, start_path, NULL);
fd0574e5 506 if (error < GIT_SUCCESS)
5ad739e8 507 return error;
fd0574e5
RG
508
509 if (!across_fs) {
510 error = retrieve_device(&current_device, bare_path);
fd0574e5 511 if (error < GIT_SUCCESS)
5ad739e8 512 return error;
fd0574e5
RG
513 }
514
515 ceiling_offset = retrieve_ceiling_directories_offset(bare_path, ceiling_dirs);
f79026b4 516 git_path_join(normal_path, bare_path, DOT_GIT);
fd0574e5 517
5ad739e8
VM
518 while(1) {
519 /**
520 * If the `.git` file is regular instead of
521 * a directory, it should contain the path of the actual git repository
522 */
f79026b4 523 if (git_futils_isfile(normal_path) == GIT_SUCCESS) {
5ad739e8 524 error = read_gitfile(repository_path, normal_path, bare_path);
fd0574e5 525
fd0574e5 526 if (error < GIT_SUCCESS)
5ad739e8 527 return git__rethrow(error, "Unable to read git file `%s`", normal_path);
fd0574e5 528
5ad739e8
VM
529 error = quickcheck_repository_dir(repository_path);
530 if (error < GIT_SUCCESS)
531 return git__throw(GIT_ENOTFOUND, "The `.git` file found at '%s' points"
532 "to an inexisting Git folder", normal_path);
fd0574e5
RG
533
534 return GIT_SUCCESS;
535 }
536
5ad739e8
VM
537 /**
538 * If the `.git` file is a folder, we check inside of it
539 */
540 if (git_futils_isdir(normal_path) == GIT_SUCCESS) {
541 error = quickcheck_repository_dir(normal_path);
542 if (error == GIT_SUCCESS) {
543 found_path = normal_path;
544 break;
545 }
fd0574e5
RG
546 }
547
5ad739e8
VM
548 /**
549 * Otherwise, the repository may be bare, let's check
550 * the root anyway
551 */
552 error = quickcheck_repository_dir(bare_path);
fd0574e5
RG
553 if (error == GIT_SUCCESS) {
554 found_path = bare_path;
555 break;
556 }
557
f79026b4 558 if (git_path_dirname_r(normal_path, sizeof(normal_path), bare_path) < GIT_SUCCESS)
5ad739e8 559 return git__throw(GIT_EOSERR, "Failed to dirname '%s'", bare_path);
fd0574e5
RG
560
561 if (!across_fs) {
562 dev_t new_device;
563 error = retrieve_device(&new_device, normal_path);
564
5ad739e8
VM
565 if (error < GIT_SUCCESS || current_device != new_device) {
566 return git__throw(GIT_ENOTAREPO,"Not a git repository (or any parent up to mount parent %s)\n"
567 "Stopping at filesystem boundary.", bare_path);
fd0574e5
RG
568 }
569 current_device = new_device;
570 }
571
572 strcpy(bare_path, normal_path);
f79026b4 573 git_path_join(normal_path, bare_path, DOT_GIT);
9d9bab5c 574
5ad739e8 575 // nothing has been found, lets try the parent directory
9d9bab5c 576 if (bare_path[ceiling_offset] == '\0') {
5ad739e8 577 return git__throw(GIT_ENOTAREPO,"Not a git repository (or any of the parent directories): %s", start_path);
9d9bab5c 578 }
fd0574e5
RG
579 }
580
5ad739e8
VM
581 if (size < (strlen(found_path) + 2) * sizeof(char)) {
582 return git__throw(GIT_EOVERFLOW, "The repository buffer is not long enough to handle the repository path `%s`", found_path);
fd0574e5
RG
583 }
584
5ad739e8 585 git_path_join(repository_path, found_path, "");
fd0574e5 586 return GIT_SUCCESS;
fd0574e5
RG
587}
588
46f8566a
VM
589git_odb *git_repository_database(git_repository *repo)
590{
591 assert(repo);
592 return repo->db;
593}
594
1bc83ff1 595static int repo_init_reinit(const char *repository_path, int is_bare)
40c44d2f
VM
596{
597 /* TODO: reinit the repository */
1bc83ff1
VM
598 return git__throw(GIT_ENOTIMPLEMENTED,
599 "Failed to reinitialize the %srepository at '%s'. "
600 "This feature is not yet implemented",
601 is_bare ? "bare" : "", repository_path);
4b8e27c8 602}
603
d2d6912e 604static int repo_init_createhead(git_repository *repo)
e1f8cad0 605{
d2d6912e 606 git_reference *head_reference;
d5afc039 607 return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE, 0);
d2d6912e 608}
e1f8cad0 609
ed72182b 610static int repo_init_structure(const char *git_dir, int is_bare)
4b8e27c8 611{
a67a096a 612 const int mode = 0755; /* or 0777 ? */
3abe3bba 613 int error;
4b8e27c8 614
40c44d2f 615 char temp_path[GIT_PATH_MAX];
4b8e27c8 616
f79026b4 617 if (git_futils_mkdir_r(git_dir, mode))
4f664a1b 618 return git__throw(GIT_ERROR, "Failed to initialize repository structure. Could not mkdir");
a67a096a 619
6ac91dfe 620 /* Hides the ".git" directory */
ed72182b 621 if (!is_bare) {
17837602 622#ifdef GIT_WIN32
f79026b4 623 error = p_hide_directory__w32(git_dir);
6ac91dfe 624 if (error < GIT_SUCCESS)
625 return git__rethrow(error, "Failed to initialize repository structure");
6ac91dfe 626#endif
17837602 627 }
6ac91dfe 628
8ea2c83b 629 /* Creates the '/objects/info/' directory */
f79026b4
VM
630 git_path_join(temp_path, git_dir, GIT_OBJECTS_INFO_DIR);
631 error = git_futils_mkdir_r(temp_path, mode);
3abe3bba 632 if (error < GIT_SUCCESS)
4f664a1b 633 return git__rethrow(error, "Failed to initialize repository structure");
a67a096a 634
8ea2c83b 635 /* Creates the '/objects/pack/' directory */
f79026b4
VM
636 git_path_join(temp_path, git_dir, GIT_OBJECTS_PACK_DIR);
637 error = p_mkdir(temp_path, mode);
3abe3bba 638 if (error < GIT_SUCCESS)
639 return git__throw(error, "Unable to create `%s` folder", temp_path);
a67a096a 640
1c2c7c0d 641 /* Creates the '/refs/heads/' directory */
f79026b4
VM
642 git_path_join(temp_path, git_dir, GIT_REFS_HEADS_DIR);
643 error = git_futils_mkdir_r(temp_path, mode);
3abe3bba 644 if (error < GIT_SUCCESS)
4f664a1b 645 return git__rethrow(error, "Failed to initialize repository structure");
1c2c7c0d 646
647 /* Creates the '/refs/tags/' directory */
f79026b4
VM
648 git_path_join(temp_path, git_dir, GIT_REFS_TAGS_DIR);
649 error = p_mkdir(temp_path, mode);
3abe3bba 650 if (error < GIT_SUCCESS)
651 return git__throw(error, "Unable to create `%s` folder", temp_path);
1c2c7c0d 652
40c44d2f 653 /* TODO: what's left? templates? */
4b8e27c8 654
655 return GIT_SUCCESS;
656}
657
40c44d2f 658int git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare)
4b8e27c8 659{
4b8e27c8 660 int error = GIT_SUCCESS;
e0011be3 661 git_repository *repo = NULL;
1bc83ff1 662 char repository_path[GIT_PATH_MAX];
932d1baf 663
4b8e27c8 664 assert(repo_out && path);
665
1bc83ff1 666 git_path_join(repository_path, path, is_bare ? "" : GIT_DIR);
4b8e27c8 667
1bc83ff1
VM
668 if (git_futils_isdir(repository_path)) {
669 if (quickcheck_repository_dir(repository_path) == GIT_SUCCESS)
670 return repo_init_reinit(repository_path, is_bare);
671 }
d2d6912e 672
ed72182b 673 error = repo_init_structure(repository_path, is_bare);
4b8e27c8 674 if (error < GIT_SUCCESS)
675 goto cleanup;
676
e0011be3
VM
677 repo = repository_alloc();
678 if (repo == NULL) {
679 error = GIT_ENOMEM;
680 goto cleanup;
681 }
682
1bc83ff1 683 error = guess_repository_dirs(repo, repository_path);
d2d6912e 684 if (error < GIT_SUCCESS)
685 goto cleanup;
686
e0011be3 687 assert(repo->is_bare == is_bare);
d2d6912e 688
e0011be3
VM
689 error = init_odb(repo);
690 if (error < GIT_SUCCESS)
691 goto cleanup;
692
693 error = repo_init_createhead(repo);
694 if (error < GIT_SUCCESS)
695 goto cleanup;
696
697 /* should never fail */
698 assert(check_repository_dirs(repo) == GIT_SUCCESS);
699
e0011be3
VM
700 *repo_out = repo;
701 return GIT_SUCCESS;
4b8e27c8 702
703cleanup:
e0011be3 704 git_repository_free(repo);
3abe3bba 705 return git__rethrow(error, "Failed to (re)init the repository `%s`", path);
40c44d2f 706}
35502d2e 707
c682886e 708int git_repository_head_detached(git_repository *repo)
35502d2e
CMN
709{
710 git_reference *ref;
711 int error;
712 size_t GIT_UNUSED(_size);
713 git_otype type;
714
715 error = git_reference_lookup(&ref, repo, GIT_HEAD_FILE);
716 if (error < GIT_SUCCESS)
717 return error;
718
719 if (git_reference_type(ref) == GIT_REF_SYMBOLIC)
720 return 0;
721
722 error = git_odb_read_header(&_size, &type, repo->db, git_reference_oid(ref));
723 if (error < GIT_SUCCESS)
724 return error;
725
726 if (type != GIT_OBJ_COMMIT)
727 return git__throw(GIT_EOBJCORRUPTED, "HEAD is not a commit");
728
729 return 1;
730}
731
c682886e 732int git_repository_head_orphan(git_repository *repo)
35502d2e
CMN
733{
734 git_reference *ref;
735 int error;
736
737 error = git_reference_lookup(&ref, repo, GIT_HEAD_FILE);
738 if (error < GIT_SUCCESS)
739 return error;
740
741 if (git_reference_type(ref) == GIT_REF_OID)
742 return 0;
743
744 error = git_reference_resolve(&ref, ref);
745
746 return error == GIT_ENOTFOUND ? 1 : error;
747}
e0011be3 748
41233c40
VM
749int git_repository_is_empty(git_repository *repo)
750{
751 git_reference *head, *branch;
752 int error;
753
754 error = git_reference_lookup(&head, repo, "HEAD");
755 if (error < GIT_SUCCESS)
0f489fb2 756 return git__throw(error, "Corrupted repository. HEAD does not exist");
41233c40
VM
757
758 if (git_reference_type(head) != GIT_REF_SYMBOLIC)
0f489fb2
VM
759 return 0;
760
761 if (strcmp(git_reference_target(head), "refs/heads/master") != 0)
762 return 0;
41233c40 763
0f489fb2
VM
764 error = git_reference_resolve(&branch, head);
765 return error == GIT_ENOTFOUND ? 1 : error;
41233c40
VM
766}
767
602ee38b 768const char *git_repository_path(git_repository *repo, git_repository_pathid id)
4a34b3a9 769{
770 assert(repo);
4a34b3a9 771
602ee38b
VM
772 switch (id) {
773 case GIT_REPO_PATH:
774 return repo->path_repository;
775
776 case GIT_REPO_PATH_INDEX:
777 return repo->path_index;
778
779 case GIT_REPO_PATH_ODB:
780 return repo->path_odb;
781
782 case GIT_REPO_PATH_WORKDIR:
783 return repo->path_workdir;
784
785 default:
786 return NULL;
787 }
4a34b3a9 788}
fa9bcd81 789
790int git_repository_is_bare(git_repository *repo)
791{
792 assert(repo);
793 return repo->is_bare;
794}