]> git.proxmox.com Git - libgit2.git/blame - src/repository.c
Merge pull request #276 from carlosmn/development
[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
RG
41#define GIT_FILE_CONTENT_PREFIX "gitdir: "
42#define GIT_FILE_CONTENT_PREFIX_LENGTH 8
43
28990938 44#define GIT_BRANCH_MASTER "master"
45
40c44d2f 46typedef struct {
4b8e27c8 47 char *path_repository;
e52ed7a5 48 unsigned is_bare:1, has_been_reinit:1;
40c44d2f 49} repo_init;
4b8e27c8 50
e52ed7a5
VM
51/*
52 * Git repository open methods
53 *
54 * Open a repository object from its path
55 */
e0011be3
VM
56static int assign_repository_dirs(
57 git_repository *repo,
691aa968
VM
58 const char *git_dir,
59 const char *git_object_directory,
60 const char *git_index_file,
e0011be3 61 const char *git_work_tree)
691aa968
VM
62{
63 char path_aux[GIT_PATH_MAX];
eb2f3b47 64 int error = GIT_SUCCESS;
691aa968
VM
65
66 assert(repo);
67
eb2f3b47 68 if (git_dir == NULL)
4f664a1b 69 return git__throw(GIT_ENOTFOUND, "Failed to open repository. Git dir not found");
691aa968 70
26a98ec8 71 error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_dir, NULL);
eb2f3b47 72 if (error < GIT_SUCCESS)
4f664a1b 73 return git__rethrow(error, "Failed to open repository");
691aa968 74
eb2f3b47 75 /* store GIT_DIR */
691aa968 76 repo->path_repository = git__strdup(path_aux);
8212e2d7
VM
77 if (repo->path_repository == NULL)
78 return GIT_ENOMEM;
691aa968 79
d2d6912e 80 /* path to GIT_OBJECT_DIRECTORY */
691aa968 81 if (git_object_directory == NULL)
d2d6912e 82 git__joinpath(path_aux, repo->path_repository, GIT_OBJECTS_DIR);
eb2f3b47 83 else {
26a98ec8 84 error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_object_directory, NULL);
eb2f3b47 85 if (error < GIT_SUCCESS)
4f664a1b 86 return git__rethrow(error, "Failed to open repository");
eb2f3b47 87 }
691aa968 88
d2d6912e 89 /* Store GIT_OBJECT_DIRECTORY */
691aa968 90 repo->path_odb = git__strdup(path_aux);
8212e2d7
VM
91 if (repo->path_odb == NULL)
92 return GIT_ENOMEM;
691aa968 93
d2d6912e 94 /* path to GIT_WORK_TREE */
691aa968
VM
95 if (git_work_tree == NULL)
96 repo->is_bare = 1;
eb2f3b47 97 else {
26a98ec8 98 error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_work_tree, NULL);
eb2f3b47 99 if (error < GIT_SUCCESS)
4f664a1b 100 return git__rethrow(error, "Failed to open repository");
d2d6912e 101
102 /* Store GIT_WORK_TREE */
eb2f3b47 103 repo->path_workdir = git__strdup(path_aux);
8212e2d7
VM
104 if (repo->path_workdir == NULL)
105 return GIT_ENOMEM;
d2d6912e 106
107 /* Path to GIT_INDEX_FILE */
108 if (git_index_file == NULL)
109 git__joinpath(path_aux, repo->path_repository, GIT_INDEX_FILE);
110 else {
26a98ec8 111 error = gitfo_prettify_file_path(path_aux, sizeof(path_aux), git_index_file, NULL);
d2d6912e 112 if (error < GIT_SUCCESS)
4f664a1b 113 return git__rethrow(error, "Failed to open repository");
d2d6912e 114 }
115
d2d6912e 116 /* store GIT_INDEX_FILE */
117 repo->path_index = git__strdup(path_aux);
118 if (repo->path_index == NULL)
119 return GIT_ENOMEM;
eb2f3b47 120 }
121
691aa968
VM
122 return GIT_SUCCESS;
123}
124
e0011be3 125static int check_repository_dirs(git_repository *repo)
6fd195d7 126{
e0011be3 127 char path_aux[GIT_PATH_MAX];
f725931b 128
e0011be3 129 if (gitfo_isdir(repo->path_repository) < GIT_SUCCESS)
3abe3bba 130 return git__throw(GIT_ENOTAREPO, "`%s` is not a folder", repo->path_repository);
6fd195d7 131
e0011be3
VM
132 /* Ensure GIT_OBJECT_DIRECTORY exists */
133 if (gitfo_isdir(repo->path_odb) < GIT_SUCCESS)
3abe3bba 134 return git__throw(GIT_ENOTAREPO, "`%s` does not exist", repo->path_odb);
e0011be3
VM
135
136 /* Ensure HEAD file exists */
137 git__joinpath(path_aux, repo->path_repository, GIT_HEAD_FILE);
138 if (gitfo_exists(path_aux) < 0)
3abe3bba 139 return git__throw(GIT_ENOTAREPO, "HEAD file is missing");
e0011be3
VM
140
141 return GIT_SUCCESS;
142}
143
144static int guess_repository_dirs(git_repository *repo, const char *repository_path)
145{
146 char buffer[GIT_PATH_MAX];
147 const char *path_work_tree = NULL;
6fd195d7 148
d2d6912e 149 /* Git directory name */
e0011be3 150 if (git__basename_r(buffer, sizeof(buffer), repository_path) < 0)
3abe3bba 151 return git__throw(GIT_EINVALIDPATH, "Unable to parse folder name from `%s`", repository_path);
6fd195d7 152
e0011be3 153 if (strcmp(buffer, DOT_GIT) == 0) {
d2d6912e 154 /* Path to working dir */
e0011be3 155 if (git__dirname_r(buffer, sizeof(buffer), repository_path) < 0)
3abe3bba 156 return git__throw(GIT_EINVALIDPATH, "Unable to parse parent folder name from `%s`", repository_path);
e0011be3 157 path_work_tree = buffer;
6fd195d7
VM
158 }
159
e0011be3 160 return assign_repository_dirs(repo, repository_path, NULL, NULL, path_work_tree);
6fd195d7
VM
161}
162
e52ed7a5 163static git_repository *repository_alloc()
3315782c 164{
81201a4c 165 int error;
166
3315782c
VM
167 git_repository *repo = git__malloc(sizeof(git_repository));
168 if (!repo)
169 return NULL;
170
171 memset(repo, 0x0, sizeof(git_repository));
172
81201a4c 173 error = git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
174 if (error < GIT_SUCCESS) {
175 free(repo);
176 return NULL;
177 }
3315782c 178
2f8a8ab2 179 if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {
48c27f86
VM
180 free(repo);
181 return NULL;
182 }
183
6fd195d7
VM
184 return repo;
185}
186
ec3c7a16
VM
187static int init_odb(git_repository *repo)
188{
3abe3bba 189 return git_odb_open(&repo->db, repo->path_odb); /* TODO: Move odb.c to new error handling */
ec3c7a16
VM
190}
191
192int git_repository_open3(git_repository **repo_out,
193 const char *git_dir,
194 git_odb *object_database,
195 const char *git_index_file,
196 const char *git_work_tree)
197{
198 git_repository *repo;
199 int error = GIT_SUCCESS;
200
201 assert(repo_out);
202
203 if (object_database == NULL)
3abe3bba 204 return git__throw(GIT_EINVALIDARGS, "Failed to open repository. `object_database` can't be null");
ec3c7a16
VM
205
206 repo = repository_alloc();
207 if (repo == NULL)
208 return GIT_ENOMEM;
209
e0011be3 210 error = assign_repository_dirs(repo,
ec3c7a16
VM
211 git_dir,
212 NULL,
213 git_index_file,
e0011be3 214 git_work_tree);
ec3c7a16
VM
215
216 if (error < GIT_SUCCESS)
217 goto cleanup;
218
e0011be3
VM
219 error = check_repository_dirs(repo);
220 if (error < GIT_SUCCESS)
221 goto cleanup;
222
ec3c7a16
VM
223 repo->db = object_database;
224
225 *repo_out = repo;
226 return GIT_SUCCESS;
227
228cleanup:
229 git_repository_free(repo);
3abe3bba 230 return git__rethrow(error, "Failed to open repository");
ec3c7a16
VM
231}
232
233
691aa968
VM
234int git_repository_open2(git_repository **repo_out,
235 const char *git_dir,
236 const char *git_object_directory,
237 const char *git_index_file,
238 const char *git_work_tree)
239{
240 git_repository *repo;
241 int error = GIT_SUCCESS;
242
243 assert(repo_out);
244
e52ed7a5 245 repo = repository_alloc();
691aa968
VM
246 if (repo == NULL)
247 return GIT_ENOMEM;
248
e0011be3 249 error = assign_repository_dirs(repo,
691aa968
VM
250 git_dir,
251 git_object_directory,
252 git_index_file,
e0011be3
VM
253 git_work_tree);
254
255 if (error < GIT_SUCCESS)
256 goto cleanup;
691aa968 257
e0011be3 258 error = check_repository_dirs(repo);
6f02c3ba 259 if (error < GIT_SUCCESS)
691aa968
VM
260 goto cleanup;
261
ec3c7a16 262 error = init_odb(repo);
6f02c3ba 263 if (error < GIT_SUCCESS)
691aa968
VM
264 goto cleanup;
265
266 *repo_out = repo;
267 return GIT_SUCCESS;
268
269cleanup:
270 git_repository_free(repo);
3abe3bba 271 return git__rethrow(error, "Failed to open repository");
691aa968
VM
272}
273
07ff8817
VM
274int git_repository_config(
275 git_config **out,
276 git_repository *repo,
277 const char *user_config_path,
278 const char *system_config_path)
b22d1479 279{
07ff8817
VM
280 char config_path[GIT_PATH_MAX];
281 int error;
b22d1479 282
07ff8817
VM
283 assert(out && repo);
284
285 error = git_config_new(out);
b22d1479 286 if (error < GIT_SUCCESS)
07ff8817 287 return error;
b22d1479 288
07ff8817 289 git__joinpath(config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO);
2a406ab5 290 error = git_config_add_file_ondisk(*out, config_path, 3);
07ff8817 291 if (error < GIT_SUCCESS)
b22d1479 292 goto cleanup;
b22d1479 293
07ff8817
VM
294 if (user_config_path != NULL) {
295 error = git_config_add_file_ondisk(*out, user_config_path, 2);
296 if (error < GIT_SUCCESS)
297 goto cleanup;
b22d1479
CMN
298 }
299
07ff8817 300 if (system_config_path != NULL) {
2a406ab5 301 error = git_config_add_file_ondisk(*out, system_config_path, 1);
07ff8817
VM
302 if (error < GIT_SUCCESS)
303 goto cleanup;
9ba9e513
CMN
304 }
305
07ff8817 306 return GIT_SUCCESS;
b22d1479
CMN
307
308cleanup:
07ff8817 309 git_config_free(*out);
b22d1479
CMN
310 return error;
311}
312
fd0574e5
RG
313static int discover_repository_dirs(git_repository *repo, const char *path)
314{
315 int error;
316
317 error = guess_repository_dirs(repo, path);
318 if (error < GIT_SUCCESS)
319 return error;
320
321 error = check_repository_dirs(repo);
322 if (error < GIT_SUCCESS)
323 return error;
324
325 return GIT_SUCCESS;
326}
327
e0011be3 328int git_repository_open(git_repository **repo_out, const char *path)
6fd195d7
VM
329{
330 git_repository *repo;
1795f879
VM
331 int error = GIT_SUCCESS;
332
333 assert(repo_out && path);
6fd195d7 334
e52ed7a5 335 repo = repository_alloc();
6fd195d7 336 if (repo == NULL)
1795f879 337 return GIT_ENOMEM;
6fd195d7 338
fd0574e5 339 error = discover_repository_dirs(repo, path);
6f02c3ba 340 if (error < GIT_SUCCESS)
1795f879 341 goto cleanup;
3315782c 342
ec3c7a16 343 error = init_odb(repo);
6f02c3ba 344 if (error < GIT_SUCCESS)
1795f879
VM
345 goto cleanup;
346
347 *repo_out = repo;
348 return GIT_SUCCESS;
349
350cleanup:
351 git_repository_free(repo);
3abe3bba 352 return git__rethrow(error, "Failed to open repository");
3315782c
VM
353}
354
f2e6b877
RG
355static int abspath(char *buffer_out, size_t size, const char *path)
356{
357 assert(buffer_out && size >= GIT_PATH_MAX);
358
359 #ifdef GIT_WIN32
360 if (_fullpath(buffer_out, path, size) == NULL)
361 return git__throw(GIT_EOSERR, "Failed to retrieve real path: %s causing errors", buffer_out);
362 #else
363 if (realpath(path, buffer_out) == NULL)
364 return git__throw(GIT_EOSERR, "Failed to retrieve real path: %s causing errors", buffer_out);
365 #endif
366
367 gitfo_posixify_path(buffer_out);
368
369 return GIT_SUCCESS;
370}
371
5ec05d07 372static int retrieve_device(dev_t *device_out, const char *path)
f2e6b877
RG
373{
374 struct stat path_info;
375
376 assert(device_out);
377
378 if (gitfo_stat(path, &path_info))
379 return git__throw(GIT_EOSERR, "Failed to get file informations: %s", path);
380
381 *device_out = path_info.st_dev;
382
383 return GIT_SUCCESS;
384}
385
386static int retrieve_ceiling_directories_offset(const char *path, const char *ceiling_directories)
387{
388 char buf[GIT_PATH_MAX + 1];
389 char buf2[GIT_PATH_MAX + 1];
390 const char *ceil, *sep;
391 int len, max_len = -1;
392 int min_len;
393
394 assert(path);
395
396 min_len = gitfo_retrieve_path_root_offset(path) + 1;
397
398 if (ceiling_directories == NULL || min_len == 0)
399 return min_len;
400
401 for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) {
402 for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);
403 len = sep - ceil;
404
405 if (len == 0 || len > GIT_PATH_MAX || gitfo_retrieve_path_root_offset(ceil) == -1)
406 continue;
407
408 strncpy(buf, ceil, len);
409 buf[len] = '\0';
410
9d9bab5c 411 if (abspath(buf2, sizeof(buf2), buf) < GIT_SUCCESS)
f2e6b877
RG
412 continue;
413
414 len = strlen(buf2);
415 if (len > 0 && buf2[len-1] == '/')
416 buf[--len] = '\0';
417
418 if (!strncmp(path, buf2, len) &&
419 path[len] == '/' &&
420 len > max_len)
421 {
422 max_len = len;
423 }
424 }
425
426 return max_len <= min_len ? min_len : max_len;
427}
428
6a01b6bd
RG
429static int read_gitfile(char *path_out, size_t size, const char *file_path, const char *base_path)
430{
431 gitfo_buf file;
432 int error, end_offset;
433 char *data;
434
435 assert(file_path && path_out && size > 0);
436
437 error = gitfo_read_file(&file, file_path);
438
439 if (error < GIT_SUCCESS)
440 return error;
441
442 data = (char*)(file.data);
443
444 if (git__prefixcmp(data, GIT_FILE_CONTENT_PREFIX)) {
445 gitfo_free_buf(&file);
446 return git__throw(GIT_ENOTFOUND, "Invalid gitfile format `%s`", file_path);
447 }
448
449 end_offset = strlen(data) - 1;
450
8b05e780
RG
451 for (;data[end_offset] == '\r' || data[end_offset] == '\n'; --end_offset);
452 data[end_offset + 1] = '\0';
6a01b6bd 453
efcc87c9 454 if (GIT_FILE_CONTENT_PREFIX_LENGTH == end_offset + 1) {
6a01b6bd
RG
455 gitfo_free_buf(&file);
456 return git__throw(GIT_ENOTFOUND, "No path in git file `%s`", file_path);
457 }
458
459 error = gitfo_prettify_dir_path(path_out, size, data + GIT_FILE_CONTENT_PREFIX_LENGTH, base_path);
f2a60854
RG
460 if (error == GIT_SUCCESS) {
461 end_offset = strlen(path_out);
462
463 if (end_offset > 0 && path_out[end_offset - 1] == '/')
464 path_out[end_offset - 1 ] = '\0';
465 }
466
6a01b6bd
RG
467 gitfo_free_buf(&file);
468
469 return error;
470}
471
222cf1d4
RG
472static void git_repository__free_dirs(git_repository *repo)
473{
474 free(repo->path_workdir);
475 repo->path_workdir = NULL;
476 free(repo->path_index);
477 repo->path_index = NULL;
478 free(repo->path_repository);
479 repo->path_repository = NULL;
480 free(repo->path_odb);
481 repo->path_odb = NULL;
482}
483
584f49a5
VM
484void git_repository_free(git_repository *repo)
485{
584f49a5
VM
486 if (repo == NULL)
487 return;
6fd195d7 488
72a3fe42
VM
489 git_cache_free(&repo->objects);
490 git_repository__refcache_free(&repo->references);
222cf1d4 491 git_repository__free_dirs(repo);
6b2a1941 492
6b2a1941
VM
493 if (repo->db != NULL)
494 git_odb_close(repo->db);
495
6b2a1941 496 free(repo);
3315782c
VM
497}
498
fd0574e5
RG
499int git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs)
500{
501 git_repository repo;
502 int error, ceiling_offset;
503 char bare_path[GIT_PATH_MAX];
504 char normal_path[GIT_PATH_MAX];
505 char *found_path;
393a9f9e 506 dev_t current_device = 0;
fd0574e5
RG
507
508 assert(start_path && repository_path);
509 memset(&repo, 0x0, sizeof(git_repository));
510
511 error = abspath(bare_path, sizeof(bare_path), start_path);
512
513 if (error < GIT_SUCCESS)
514 goto cleanup;
515
516 if (!across_fs) {
517 error = retrieve_device(&current_device, bare_path);
518
519 if (error < GIT_SUCCESS)
520 goto cleanup;
521 }
522
523 ceiling_offset = retrieve_ceiling_directories_offset(bare_path, ceiling_dirs);
524 git__joinpath(normal_path, bare_path, DOT_GIT);
525
526 while(1){
527 //look for .git file
528 if (gitfo_isfile(normal_path) == GIT_SUCCESS) {
529 error = read_gitfile(repository_path, size, normal_path, bare_path);
530
531 if (error < GIT_SUCCESS) {
532 git__rethrow(error, "Unable to read git file `%s`", normal_path);
533 goto cleanup;
534 }
535
536 error = discover_repository_dirs(&repo, repository_path);
537 if (error < GIT_SUCCESS)
538 goto cleanup;
539
540 git_repository__free_dirs(&repo);
541
542 return GIT_SUCCESS;
543 }
544
545 //look for .git repository
546 error = discover_repository_dirs(&repo, normal_path);
547 if (error < GIT_SUCCESS && error != GIT_ENOTAREPO)
548 goto cleanup;
549
550 if (error == GIT_SUCCESS) {
551 found_path = normal_path;
552 break;
553 }
554
555 git_repository__free_dirs(&repo);
556
557 //look for bare repository in current directory
558 error = discover_repository_dirs(&repo, bare_path);
559 if (error < GIT_SUCCESS && error != GIT_ENOTAREPO)
560 goto cleanup;
561
562 if (error == GIT_SUCCESS) {
563 found_path = bare_path;
564 break;
565 }
566
567 git_repository__free_dirs(&repo);
568
fd0574e5
RG
569 if (git__dirname_r(normal_path, sizeof(normal_path), bare_path) < GIT_SUCCESS)
570 goto cleanup;
571
572 if (!across_fs) {
573 dev_t new_device;
574 error = retrieve_device(&new_device, normal_path);
575
576 if (error < GIT_SUCCESS)
577 goto cleanup;
578
579 if (current_device != new_device) {
580 error = git__throw(GIT_ENOTAREPO,"Not a git repository (or any parent up to mount parent %s)\n"
581 "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM_ENVIRONMENT not set).", bare_path);
582 goto cleanup;
583 }
584 current_device = new_device;
585 }
586
587 strcpy(bare_path, normal_path);
588 git__joinpath(normal_path, bare_path, DOT_GIT);
9d9bab5c
RG
589
590 //nothing has been found, lets try the parent directory
591 if (bare_path[ceiling_offset] == '\0') {
592 error = git__throw(GIT_ENOTAREPO,"Not a git repository (or any of the parent directories): %s", start_path);
593 goto cleanup;
594 }
595
fd0574e5
RG
596 }
597
598 if (size < (strlen(found_path) + 1) * sizeof(char)) {
599 error = git__throw(GIT_EOVERFLOW, "The repository buffer is not long enough to handle the repository path `%s`", found_path);
600 goto cleanup;
601 }
602
603 strcpy(repository_path, found_path);
604 git_repository__free_dirs(&repo);
605
606 return GIT_SUCCESS;
607
608 cleanup:
609 git_repository__free_dirs(&repo);
610 return git__rethrow(error, "Failed to discover repository");
611}
612
46f8566a
VM
613git_odb *git_repository_database(git_repository *repo)
614{
615 assert(repo);
616 return repo->db;
617}
618
fb3cd6bc 619static int repo_init_reinit(repo_init *results)
40c44d2f
VM
620{
621 /* TODO: reinit the repository */
4b8e27c8 622 results->has_been_reinit = 1;
4f664a1b 623 return git__throw(GIT_ENOTIMPLEMENTED, "Failed to reinitialize the repository. This feature is not yet implemented");
4b8e27c8 624}
625
d2d6912e 626static int repo_init_createhead(git_repository *repo)
e1f8cad0 627{
d2d6912e 628 git_reference *head_reference;
3abe3bba 629 return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE); /* TODO: finalize moving refs.c to new error handling */
d2d6912e 630}
e1f8cad0 631
d2d6912e 632static int repo_init_check_head_existence(char * repository_path)
633{
634 char temp_path[GIT_PATH_MAX];
e1f8cad0 635
d2d6912e 636 git__joinpath(temp_path, repository_path, GIT_HEAD_FILE);
637 return gitfo_exists(temp_path);
e1f8cad0 638}
639
fb3cd6bc 640static int repo_init_structure(repo_init *results)
4b8e27c8 641{
a67a096a 642 const int mode = 0755; /* or 0777 ? */
3abe3bba 643 int error;
4b8e27c8 644
40c44d2f 645 char temp_path[GIT_PATH_MAX];
40c44d2f 646 char *git_dir = results->path_repository;
4b8e27c8 647
a67a096a 648 if (gitfo_mkdir_recurs(git_dir, mode))
4f664a1b 649 return git__throw(GIT_ERROR, "Failed to initialize repository structure. Could not mkdir");
a67a096a 650
8ea2c83b 651 /* Creates the '/objects/info/' directory */
874c3b6f 652 git__joinpath(temp_path, git_dir, GIT_OBJECTS_INFO_DIR);
3abe3bba 653 error = gitfo_mkdir_recurs(temp_path, mode);
654 if (error < GIT_SUCCESS)
4f664a1b 655 return git__rethrow(error, "Failed to initialize repository structure");
a67a096a 656
8ea2c83b 657 /* Creates the '/objects/pack/' directory */
874c3b6f 658 git__joinpath(temp_path, git_dir, GIT_OBJECTS_PACK_DIR);
3abe3bba 659 error = gitfo_mkdir(temp_path, mode);
660 if (error < GIT_SUCCESS)
661 return git__throw(error, "Unable to create `%s` folder", temp_path);
a67a096a 662
1c2c7c0d 663 /* Creates the '/refs/heads/' directory */
874c3b6f 664 git__joinpath(temp_path, git_dir, GIT_REFS_HEADS_DIR);
3abe3bba 665 error = gitfo_mkdir_recurs(temp_path, mode);
666 if (error < GIT_SUCCESS)
4f664a1b 667 return git__rethrow(error, "Failed to initialize repository structure");
1c2c7c0d 668
669 /* Creates the '/refs/tags/' directory */
874c3b6f 670 git__joinpath(temp_path, git_dir, GIT_REFS_TAGS_DIR);
3abe3bba 671 error = gitfo_mkdir(temp_path, mode);
672 if (error < GIT_SUCCESS)
673 return git__throw(error, "Unable to create `%s` folder", temp_path);
1c2c7c0d 674
40c44d2f 675 /* TODO: what's left? templates? */
4b8e27c8 676
677 return GIT_SUCCESS;
678}
679
fb3cd6bc 680static int repo_init_find_dir(repo_init *results, const char* path)
4b8e27c8 681{
4b8e27c8 682 char temp_path[GIT_PATH_MAX];
9dd34b1e 683 int error = GIT_SUCCESS;
4b8e27c8 684
26a98ec8 685 error = gitfo_prettify_dir_path(temp_path, sizeof(temp_path), path, NULL);
9dd34b1e 686 if (error < GIT_SUCCESS)
4f664a1b 687 return git__rethrow(error, "Failed to find directory to initialize repository");
4b8e27c8 688
40c44d2f 689 if (!results->is_bare) {
874c3b6f 690 git__joinpath(temp_path, temp_path, GIT_DIR);
4b8e27c8 691 }
692
693 results->path_repository = git__strdup(temp_path);
8212e2d7
VM
694 if (results->path_repository == NULL)
695 return GIT_ENOMEM;
4b8e27c8 696
697 return GIT_SUCCESS;
698}
699
40c44d2f 700int git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare)
4b8e27c8 701{
4b8e27c8 702 int error = GIT_SUCCESS;
e0011be3 703 git_repository *repo = NULL;
40c44d2f 704 repo_init results;
4b8e27c8 705
706 assert(repo_out && path);
707
40c44d2f 708 results.path_repository = NULL;
08190e2a 709 results.is_bare = is_bare;
4b8e27c8 710
40c44d2f 711 error = repo_init_find_dir(&results, path);
4b8e27c8 712 if (error < GIT_SUCCESS)
713 goto cleanup;
714
d2d6912e 715 if (!repo_init_check_head_existence(results.path_repository))
716 return repo_init_reinit(&results);
717
40c44d2f 718 error = repo_init_structure(&results);
4b8e27c8 719 if (error < GIT_SUCCESS)
720 goto cleanup;
721
e0011be3
VM
722 repo = repository_alloc();
723 if (repo == NULL) {
724 error = GIT_ENOMEM;
725 goto cleanup;
726 }
727
728 error = guess_repository_dirs(repo, results.path_repository);
d2d6912e 729 if (error < GIT_SUCCESS)
730 goto cleanup;
731
e0011be3 732 assert(repo->is_bare == is_bare);
d2d6912e 733
e0011be3
VM
734 error = init_odb(repo);
735 if (error < GIT_SUCCESS)
736 goto cleanup;
737
738 error = repo_init_createhead(repo);
739 if (error < GIT_SUCCESS)
740 goto cleanup;
741
742 /* should never fail */
743 assert(check_repository_dirs(repo) == GIT_SUCCESS);
744
745 free(results.path_repository);
746 *repo_out = repo;
747 return GIT_SUCCESS;
4b8e27c8 748
749cleanup:
58fcfc26 750 free(results.path_repository);
e0011be3 751 git_repository_free(repo);
3abe3bba 752 return git__rethrow(error, "Failed to (re)init the repository `%s`", path);
40c44d2f 753}
e0011be3 754
41233c40
VM
755int git_repository_is_empty(git_repository *repo)
756{
757 git_reference *head, *branch;
758 int error;
759
760 error = git_reference_lookup(&head, repo, "HEAD");
761 if (error < GIT_SUCCESS)
3abe3bba 762 return git__throw(error, "Failed to determine the emptiness of the repository. An error occured while retrieving the HEAD reference");
41233c40
VM
763
764 if (git_reference_type(head) != GIT_REF_SYMBOLIC)
3abe3bba 765 return git__throw(GIT_EOBJCORRUPTED, "Failed to determine the emptiness of the repository. HEAD is probably in detached state");
41233c40
VM
766
767 return git_reference_resolve(&branch, head) == GIT_SUCCESS ? 0 : 1;
768}
769
602ee38b 770const char *git_repository_path(git_repository *repo, git_repository_pathid id)
4a34b3a9 771{
772 assert(repo);
4a34b3a9 773
602ee38b
VM
774 switch (id) {
775 case GIT_REPO_PATH:
776 return repo->path_repository;
777
778 case GIT_REPO_PATH_INDEX:
779 return repo->path_index;
780
781 case GIT_REPO_PATH_ODB:
782 return repo->path_odb;
783
784 case GIT_REPO_PATH_WORKDIR:
785 return repo->path_workdir;
786
787 default:
788 return NULL;
789 }
4a34b3a9 790}
fa9bcd81 791
792int git_repository_is_bare(git_repository *repo)
793{
794 assert(repo);
795 return repo->is_bare;
796}