]> git.proxmox.com Git - libgit2.git/blame - src/repository.c
Remove double-space
[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"
3315782c 35
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
fd0574e5
RG
274static int discover_repository_dirs(git_repository *repo, const char *path)
275{
276 int error;
277
278 error = guess_repository_dirs(repo, path);
279 if (error < GIT_SUCCESS)
280 return error;
281
282 error = check_repository_dirs(repo);
283 if (error < GIT_SUCCESS)
284 return error;
285
286 return GIT_SUCCESS;
287}
288
e0011be3 289int git_repository_open(git_repository **repo_out, const char *path)
6fd195d7
VM
290{
291 git_repository *repo;
1795f879
VM
292 int error = GIT_SUCCESS;
293
294 assert(repo_out && path);
6fd195d7 295
e52ed7a5 296 repo = repository_alloc();
6fd195d7 297 if (repo == NULL)
1795f879 298 return GIT_ENOMEM;
6fd195d7 299
fd0574e5 300 error = discover_repository_dirs(repo, path);
6f02c3ba 301 if (error < GIT_SUCCESS)
1795f879 302 goto cleanup;
3315782c 303
ec3c7a16 304 error = init_odb(repo);
6f02c3ba 305 if (error < GIT_SUCCESS)
1795f879
VM
306 goto cleanup;
307
308 *repo_out = repo;
309 return GIT_SUCCESS;
310
311cleanup:
312 git_repository_free(repo);
3abe3bba 313 return git__rethrow(error, "Failed to open repository");
3315782c
VM
314}
315
f2e6b877
RG
316static int abspath(char *buffer_out, size_t size, const char *path)
317{
318 assert(buffer_out && size >= GIT_PATH_MAX);
319
320 #ifdef GIT_WIN32
321 if (_fullpath(buffer_out, path, size) == NULL)
322 return git__throw(GIT_EOSERR, "Failed to retrieve real path: %s causing errors", buffer_out);
323 #else
324 if (realpath(path, buffer_out) == NULL)
325 return git__throw(GIT_EOSERR, "Failed to retrieve real path: %s causing errors", buffer_out);
326 #endif
327
328 gitfo_posixify_path(buffer_out);
329
330 return GIT_SUCCESS;
331}
332
5ec05d07 333static int retrieve_device(dev_t *device_out, const char *path)
f2e6b877
RG
334{
335 struct stat path_info;
336
337 assert(device_out);
338
339 if (gitfo_stat(path, &path_info))
340 return git__throw(GIT_EOSERR, "Failed to get file informations: %s", path);
341
342 *device_out = path_info.st_dev;
343
344 return GIT_SUCCESS;
345}
346
347static int retrieve_ceiling_directories_offset(const char *path, const char *ceiling_directories)
348{
349 char buf[GIT_PATH_MAX + 1];
350 char buf2[GIT_PATH_MAX + 1];
351 const char *ceil, *sep;
352 int len, max_len = -1;
353 int min_len;
354
355 assert(path);
356
357 min_len = gitfo_retrieve_path_root_offset(path) + 1;
358
359 if (ceiling_directories == NULL || min_len == 0)
360 return min_len;
361
362 for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) {
363 for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);
364 len = sep - ceil;
365
366 if (len == 0 || len > GIT_PATH_MAX || gitfo_retrieve_path_root_offset(ceil) == -1)
367 continue;
368
369 strncpy(buf, ceil, len);
370 buf[len] = '\0';
371
9d9bab5c 372 if (abspath(buf2, sizeof(buf2), buf) < GIT_SUCCESS)
f2e6b877
RG
373 continue;
374
375 len = strlen(buf2);
376 if (len > 0 && buf2[len-1] == '/')
377 buf[--len] = '\0';
378
379 if (!strncmp(path, buf2, len) &&
380 path[len] == '/' &&
381 len > max_len)
382 {
383 max_len = len;
384 }
385 }
386
387 return max_len <= min_len ? min_len : max_len;
388}
389
6a01b6bd
RG
390static int read_gitfile(char *path_out, size_t size, const char *file_path, const char *base_path)
391{
392 gitfo_buf file;
393 int error, end_offset;
394 char *data;
395
396 assert(file_path && path_out && size > 0);
397
398 error = gitfo_read_file(&file, file_path);
399
400 if (error < GIT_SUCCESS)
401 return error;
402
403 data = (char*)(file.data);
404
405 if (git__prefixcmp(data, GIT_FILE_CONTENT_PREFIX)) {
406 gitfo_free_buf(&file);
407 return git__throw(GIT_ENOTFOUND, "Invalid gitfile format `%s`", file_path);
408 }
409
410 end_offset = strlen(data) - 1;
411
8b05e780
RG
412 for (;data[end_offset] == '\r' || data[end_offset] == '\n'; --end_offset);
413 data[end_offset + 1] = '\0';
6a01b6bd 414
efcc87c9 415 if (GIT_FILE_CONTENT_PREFIX_LENGTH == end_offset + 1) {
6a01b6bd
RG
416 gitfo_free_buf(&file);
417 return git__throw(GIT_ENOTFOUND, "No path in git file `%s`", file_path);
418 }
419
420 error = gitfo_prettify_dir_path(path_out, size, data + GIT_FILE_CONTENT_PREFIX_LENGTH, base_path);
f2a60854
RG
421 if (error == GIT_SUCCESS) {
422 end_offset = strlen(path_out);
423
424 if (end_offset > 0 && path_out[end_offset - 1] == '/')
425 path_out[end_offset - 1 ] = '\0';
426 }
427
6a01b6bd
RG
428 gitfo_free_buf(&file);
429
430 return error;
431}
432
222cf1d4
RG
433static void git_repository__free_dirs(git_repository *repo)
434{
435 free(repo->path_workdir);
436 repo->path_workdir = NULL;
437 free(repo->path_index);
438 repo->path_index = NULL;
439 free(repo->path_repository);
440 repo->path_repository = NULL;
441 free(repo->path_odb);
442 repo->path_odb = NULL;
443}
444
584f49a5
VM
445void git_repository_free(git_repository *repo)
446{
584f49a5
VM
447 if (repo == NULL)
448 return;
6fd195d7 449
72a3fe42
VM
450 git_cache_free(&repo->objects);
451 git_repository__refcache_free(&repo->references);
222cf1d4 452 git_repository__free_dirs(repo);
6b2a1941 453
6b2a1941
VM
454 if (repo->db != NULL)
455 git_odb_close(repo->db);
456
6b2a1941 457 free(repo);
3315782c
VM
458}
459
fd0574e5
RG
460int git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs)
461{
462 git_repository repo;
463 int error, ceiling_offset;
464 char bare_path[GIT_PATH_MAX];
465 char normal_path[GIT_PATH_MAX];
466 char *found_path;
393a9f9e 467 dev_t current_device = 0;
fd0574e5
RG
468
469 assert(start_path && repository_path);
470 memset(&repo, 0x0, sizeof(git_repository));
471
472 error = abspath(bare_path, sizeof(bare_path), start_path);
473
474 if (error < GIT_SUCCESS)
475 goto cleanup;
476
477 if (!across_fs) {
478 error = retrieve_device(&current_device, bare_path);
479
480 if (error < GIT_SUCCESS)
481 goto cleanup;
482 }
483
484 ceiling_offset = retrieve_ceiling_directories_offset(bare_path, ceiling_dirs);
485 git__joinpath(normal_path, bare_path, DOT_GIT);
486
487 while(1){
488 //look for .git file
489 if (gitfo_isfile(normal_path) == GIT_SUCCESS) {
490 error = read_gitfile(repository_path, size, normal_path, bare_path);
491
492 if (error < GIT_SUCCESS) {
493 git__rethrow(error, "Unable to read git file `%s`", normal_path);
494 goto cleanup;
495 }
496
497 error = discover_repository_dirs(&repo, repository_path);
498 if (error < GIT_SUCCESS)
499 goto cleanup;
500
501 git_repository__free_dirs(&repo);
502
503 return GIT_SUCCESS;
504 }
505
506 //look for .git repository
507 error = discover_repository_dirs(&repo, normal_path);
508 if (error < GIT_SUCCESS && error != GIT_ENOTAREPO)
509 goto cleanup;
510
511 if (error == GIT_SUCCESS) {
512 found_path = normal_path;
513 break;
514 }
515
516 git_repository__free_dirs(&repo);
517
518 //look for bare repository in current directory
519 error = discover_repository_dirs(&repo, bare_path);
520 if (error < GIT_SUCCESS && error != GIT_ENOTAREPO)
521 goto cleanup;
522
523 if (error == GIT_SUCCESS) {
524 found_path = bare_path;
525 break;
526 }
527
528 git_repository__free_dirs(&repo);
529
fd0574e5
RG
530 if (git__dirname_r(normal_path, sizeof(normal_path), bare_path) < GIT_SUCCESS)
531 goto cleanup;
532
533 if (!across_fs) {
534 dev_t new_device;
535 error = retrieve_device(&new_device, normal_path);
536
537 if (error < GIT_SUCCESS)
538 goto cleanup;
539
540 if (current_device != new_device) {
541 error = git__throw(GIT_ENOTAREPO,"Not a git repository (or any parent up to mount parent %s)\n"
542 "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM_ENVIRONMENT not set).", bare_path);
543 goto cleanup;
544 }
545 current_device = new_device;
546 }
547
548 strcpy(bare_path, normal_path);
549 git__joinpath(normal_path, bare_path, DOT_GIT);
9d9bab5c
RG
550
551 //nothing has been found, lets try the parent directory
552 if (bare_path[ceiling_offset] == '\0') {
553 error = git__throw(GIT_ENOTAREPO,"Not a git repository (or any of the parent directories): %s", start_path);
554 goto cleanup;
555 }
556
fd0574e5
RG
557 }
558
559 if (size < (strlen(found_path) + 1) * sizeof(char)) {
560 error = git__throw(GIT_EOVERFLOW, "The repository buffer is not long enough to handle the repository path `%s`", found_path);
561 goto cleanup;
562 }
563
564 strcpy(repository_path, found_path);
565 git_repository__free_dirs(&repo);
566
567 return GIT_SUCCESS;
568
569 cleanup:
570 git_repository__free_dirs(&repo);
571 return git__rethrow(error, "Failed to discover repository");
572}
573
46f8566a
VM
574git_odb *git_repository_database(git_repository *repo)
575{
576 assert(repo);
577 return repo->db;
578}
579
fb3cd6bc 580static int repo_init_reinit(repo_init *results)
40c44d2f
VM
581{
582 /* TODO: reinit the repository */
4b8e27c8 583 results->has_been_reinit = 1;
4f664a1b 584 return git__throw(GIT_ENOTIMPLEMENTED, "Failed to reinitialize the repository. This feature is not yet implemented");
4b8e27c8 585}
586
d2d6912e 587static int repo_init_createhead(git_repository *repo)
e1f8cad0 588{
d2d6912e 589 git_reference *head_reference;
3abe3bba 590 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 591}
e1f8cad0 592
d2d6912e 593static int repo_init_check_head_existence(char * repository_path)
594{
595 char temp_path[GIT_PATH_MAX];
e1f8cad0 596
d2d6912e 597 git__joinpath(temp_path, repository_path, GIT_HEAD_FILE);
598 return gitfo_exists(temp_path);
e1f8cad0 599}
600
fb3cd6bc 601static int repo_init_structure(repo_init *results)
4b8e27c8 602{
a67a096a 603 const int mode = 0755; /* or 0777 ? */
3abe3bba 604 int error;
4b8e27c8 605
40c44d2f 606 char temp_path[GIT_PATH_MAX];
40c44d2f 607 char *git_dir = results->path_repository;
4b8e27c8 608
a67a096a 609 if (gitfo_mkdir_recurs(git_dir, mode))
4f664a1b 610 return git__throw(GIT_ERROR, "Failed to initialize repository structure. Could not mkdir");
a67a096a 611
8ea2c83b 612 /* Creates the '/objects/info/' directory */
874c3b6f 613 git__joinpath(temp_path, git_dir, GIT_OBJECTS_INFO_DIR);
3abe3bba 614 error = gitfo_mkdir_recurs(temp_path, mode);
615 if (error < GIT_SUCCESS)
4f664a1b 616 return git__rethrow(error, "Failed to initialize repository structure");
a67a096a 617
8ea2c83b 618 /* Creates the '/objects/pack/' directory */
874c3b6f 619 git__joinpath(temp_path, git_dir, GIT_OBJECTS_PACK_DIR);
3abe3bba 620 error = gitfo_mkdir(temp_path, mode);
621 if (error < GIT_SUCCESS)
622 return git__throw(error, "Unable to create `%s` folder", temp_path);
a67a096a 623
1c2c7c0d 624 /* Creates the '/refs/heads/' directory */
874c3b6f 625 git__joinpath(temp_path, git_dir, GIT_REFS_HEADS_DIR);
3abe3bba 626 error = gitfo_mkdir_recurs(temp_path, mode);
627 if (error < GIT_SUCCESS)
4f664a1b 628 return git__rethrow(error, "Failed to initialize repository structure");
1c2c7c0d 629
630 /* Creates the '/refs/tags/' directory */
874c3b6f 631 git__joinpath(temp_path, git_dir, GIT_REFS_TAGS_DIR);
3abe3bba 632 error = gitfo_mkdir(temp_path, mode);
633 if (error < GIT_SUCCESS)
634 return git__throw(error, "Unable to create `%s` folder", temp_path);
1c2c7c0d 635
40c44d2f 636 /* TODO: what's left? templates? */
4b8e27c8 637
638 return GIT_SUCCESS;
639}
640
fb3cd6bc 641static int repo_init_find_dir(repo_init *results, const char* path)
4b8e27c8 642{
4b8e27c8 643 char temp_path[GIT_PATH_MAX];
9dd34b1e 644 int error = GIT_SUCCESS;
4b8e27c8 645
26a98ec8 646 error = gitfo_prettify_dir_path(temp_path, sizeof(temp_path), path, NULL);
9dd34b1e 647 if (error < GIT_SUCCESS)
4f664a1b 648 return git__rethrow(error, "Failed to find directory to initialize repository");
4b8e27c8 649
40c44d2f 650 if (!results->is_bare) {
874c3b6f 651 git__joinpath(temp_path, temp_path, GIT_DIR);
4b8e27c8 652 }
653
654 results->path_repository = git__strdup(temp_path);
8212e2d7
VM
655 if (results->path_repository == NULL)
656 return GIT_ENOMEM;
4b8e27c8 657
658 return GIT_SUCCESS;
659}
660
40c44d2f 661int git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare)
4b8e27c8 662{
4b8e27c8 663 int error = GIT_SUCCESS;
e0011be3 664 git_repository *repo = NULL;
40c44d2f 665 repo_init results;
4b8e27c8 666
667 assert(repo_out && path);
668
40c44d2f 669 results.path_repository = NULL;
08190e2a 670 results.is_bare = is_bare;
4b8e27c8 671
40c44d2f 672 error = repo_init_find_dir(&results, path);
4b8e27c8 673 if (error < GIT_SUCCESS)
674 goto cleanup;
675
d2d6912e 676 if (!repo_init_check_head_existence(results.path_repository))
677 return repo_init_reinit(&results);
678
40c44d2f 679 error = repo_init_structure(&results);
4b8e27c8 680 if (error < GIT_SUCCESS)
681 goto cleanup;
682
e0011be3
VM
683 repo = repository_alloc();
684 if (repo == NULL) {
685 error = GIT_ENOMEM;
686 goto cleanup;
687 }
688
689 error = guess_repository_dirs(repo, results.path_repository);
d2d6912e 690 if (error < GIT_SUCCESS)
691 goto cleanup;
692
e0011be3 693 assert(repo->is_bare == is_bare);
d2d6912e 694
e0011be3
VM
695 error = init_odb(repo);
696 if (error < GIT_SUCCESS)
697 goto cleanup;
698
699 error = repo_init_createhead(repo);
700 if (error < GIT_SUCCESS)
701 goto cleanup;
702
703 /* should never fail */
704 assert(check_repository_dirs(repo) == GIT_SUCCESS);
705
706 free(results.path_repository);
707 *repo_out = repo;
708 return GIT_SUCCESS;
4b8e27c8 709
710cleanup:
58fcfc26 711 free(results.path_repository);
e0011be3 712 git_repository_free(repo);
3abe3bba 713 return git__rethrow(error, "Failed to (re)init the repository `%s`", path);
40c44d2f 714}
e0011be3 715
41233c40
VM
716int git_repository_is_empty(git_repository *repo)
717{
718 git_reference *head, *branch;
719 int error;
720
721 error = git_reference_lookup(&head, repo, "HEAD");
722 if (error < GIT_SUCCESS)
3abe3bba 723 return git__throw(error, "Failed to determine the emptiness of the repository. An error occured while retrieving the HEAD reference");
41233c40
VM
724
725 if (git_reference_type(head) != GIT_REF_SYMBOLIC)
3abe3bba 726 return git__throw(GIT_EOBJCORRUPTED, "Failed to determine the emptiness of the repository. HEAD is probably in detached state");
41233c40
VM
727
728 return git_reference_resolve(&branch, head) == GIT_SUCCESS ? 0 : 1;
729}
730
602ee38b 731const char *git_repository_path(git_repository *repo, git_repository_pathid id)
4a34b3a9 732{
733 assert(repo);
4a34b3a9 734
602ee38b
VM
735 switch (id) {
736 case GIT_REPO_PATH:
737 return repo->path_repository;
738
739 case GIT_REPO_PATH_INDEX:
740 return repo->path_index;
741
742 case GIT_REPO_PATH_ODB:
743 return repo->path_odb;
744
745 case GIT_REPO_PATH_WORKDIR:
746 return repo->path_workdir;
747
748 default:
749 return NULL;
750 }
4a34b3a9 751}
fa9bcd81 752
753int git_repository_is_bare(git_repository *repo)
754{
755 assert(repo);
756 return repo->is_bare;
757}