]> git.proxmox.com Git - libgit2.git/blame - src/repository.c
clean up temp repo for t12-repo tests
[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
28990938 41#define GIT_BRANCH_MASTER "master"
42
e52ed7a5 43static const int OBJECT_TABLE_SIZE = 32;
d45b4a9a 44
40c44d2f 45typedef struct {
4b8e27c8 46 char *path_repository;
e52ed7a5 47 unsigned is_bare:1, has_been_reinit:1;
40c44d2f 48} repo_init;
4b8e27c8 49
e52ed7a5
VM
50/*
51 * Hash table methods
d12299fe 52 *
e52ed7a5
VM
53 * Callbacks for the ODB cache, implemented
54 * as a hash table
55 */
fc658755 56uint32_t object_table_hash(const void *key, int hash_id)
3315782c
VM
57{
58 uint32_t r;
59 git_oid *id;
60
61 id = (git_oid *)key;
fc658755 62 memcpy(&r, id->id + (hash_id * sizeof(uint32_t)), sizeof(r));
3315782c
VM
63 return r;
64}
65
e52ed7a5
VM
66/*
67 * Git repository open methods
68 *
69 * Open a repository object from its path
70 */
40c44d2f 71static int assign_repository_DIRs(git_repository *repo,
691aa968
VM
72 const char *git_dir,
73 const char *git_object_directory,
74 const char *git_index_file,
d2d6912e 75 const char *git_work_tree,
76 int is_repo_being_created)
691aa968
VM
77{
78 char path_aux[GIT_PATH_MAX];
eb2f3b47 79 size_t git_dir_path_len;
80 int error = GIT_SUCCESS;
691aa968
VM
81
82 assert(repo);
83
eb2f3b47 84 if (git_dir == NULL)
691aa968
VM
85 return GIT_ENOTFOUND;
86
2e6fd09c 87 error = gitfo_prettify_dir_path(path_aux, git_dir);
eb2f3b47 88 if (error < GIT_SUCCESS)
89 return error;
691aa968 90
eb2f3b47 91 git_dir_path_len = strlen(path_aux);
691aa968 92
eb2f3b47 93 /* store GIT_DIR */
691aa968 94 repo->path_repository = git__strdup(path_aux);
8212e2d7
VM
95 if (repo->path_repository == NULL)
96 return GIT_ENOMEM;
691aa968 97
d2d6912e 98 /* path to GIT_OBJECT_DIRECTORY */
691aa968 99 if (git_object_directory == NULL)
d2d6912e 100 git__joinpath(path_aux, repo->path_repository, GIT_OBJECTS_DIR);
eb2f3b47 101 else {
2e6fd09c 102 error = gitfo_prettify_dir_path(path_aux, git_object_directory);
eb2f3b47 103 if (error < GIT_SUCCESS)
104 return error;
105 }
691aa968 106
d2d6912e 107 /* Ensure GIT_OBJECT_DIRECTORY exists */
6f02c3ba 108 if (gitfo_isdir(path_aux) < GIT_SUCCESS)
691aa968
VM
109 return GIT_ENOTFOUND;
110
d2d6912e 111 /* Store GIT_OBJECT_DIRECTORY */
691aa968 112 repo->path_odb = git__strdup(path_aux);
8212e2d7
VM
113 if (repo->path_odb == NULL)
114 return GIT_ENOMEM;
691aa968 115
d2d6912e 116 if (!is_repo_being_created) {
117 /* Ensure HEAD file exists */
118 git__joinpath(path_aux, repo->path_repository, GIT_HEAD_FILE);
119 if (gitfo_exists(path_aux) < 0)
120 return GIT_ENOTAREPO;
eb2f3b47 121 }
691aa968 122
d2d6912e 123 /* path to GIT_WORK_TREE */
691aa968
VM
124 if (git_work_tree == NULL)
125 repo->is_bare = 1;
eb2f3b47 126 else {
2e6fd09c 127 error = gitfo_prettify_dir_path(path_aux, git_work_tree);
eb2f3b47 128 if (error < GIT_SUCCESS)
129 return error;
d2d6912e 130
131 /* Store GIT_WORK_TREE */
eb2f3b47 132 repo->path_workdir = git__strdup(path_aux);
8212e2d7
VM
133 if (repo->path_workdir == NULL)
134 return GIT_ENOMEM;
d2d6912e 135
136 /* Path to GIT_INDEX_FILE */
137 if (git_index_file == NULL)
138 git__joinpath(path_aux, repo->path_repository, GIT_INDEX_FILE);
139 else {
140 error = gitfo_prettify_file_path(path_aux, git_index_file);
141 if (error < GIT_SUCCESS)
142 return error;
143 }
144
145 if (!is_repo_being_created) {
146 /* Ensure GIT_INDEX_FILE exists */
147 if (gitfo_exists(path_aux) < 0)
148 return GIT_ENOTAREPO;
149 }
150
151 /* store GIT_INDEX_FILE */
152 repo->path_index = git__strdup(path_aux);
153 if (repo->path_index == NULL)
154 return GIT_ENOMEM;
eb2f3b47 155 }
156
691aa968
VM
157 return GIT_SUCCESS;
158}
159
d2d6912e 160static int guess_repository_DIRs(git_repository *repo, const char *repository_path, int is_repo_being_created)
6fd195d7 161{
d2d6912e 162 char path_odb[GIT_PATH_MAX] = "\0", path_index[GIT_PATH_MAX] = "\0", path_work_tree[GIT_PATH_MAX] = "\0";
163 char dir_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
f725931b 164
9dd34b1e 165 int error = GIT_SUCCESS;
6fd195d7 166
d2d6912e 167 /* Path to objects database */
168 git__joinpath(path_odb, repository_path, GIT_OBJECTS_DIR);
6fd195d7 169
d2d6912e 170 /* Git directory name */
171 if (git__basename_r(dir_name, sizeof(dir_name), repository_path) < 0)
f725931b 172 return GIT_EINVALIDPATH;
6fd195d7 173
d2d6912e 174 if (strcmp(dir_name, DOT_GIT) == 0) {
175
176 /* Path to index file */
177 git__joinpath(path_index, repository_path, GIT_INDEX_FILE);
1544bc31 178
d2d6912e 179 /* Path to working dir */
180 if (git__dirname_r(path_work_tree, sizeof(path_work_tree), repository_path) < 0)
f725931b 181 return GIT_EINVALIDPATH;
6fd195d7
VM
182 }
183
d2d6912e 184 error = assign_repository_DIRs(repo, repository_path, path_odb, !*path_index ? NULL : path_index, !*path_work_tree ? NULL : path_work_tree, is_repo_being_created);
185 return error;
6fd195d7
VM
186}
187
e52ed7a5 188static git_repository *repository_alloc()
3315782c
VM
189{
190 git_repository *repo = git__malloc(sizeof(git_repository));
191 if (!repo)
192 return NULL;
193
194 memset(repo, 0x0, sizeof(git_repository));
195
196 repo->objects = git_hashtable_alloc(
e52ed7a5
VM
197 OBJECT_TABLE_SIZE,
198 object_table_hash,
fc658755 199 (git_hash_keyeq_ptr)git_oid_cmp);
3315782c 200
fc658755 201 if (repo->objects == NULL) {
3315782c
VM
202 free(repo);
203 return NULL;
204 }
205
2f8a8ab2 206 if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {
9282e921 207 git_hashtable_free(repo->objects);
208 free(repo);
209 return NULL;
210 }
211
48c27f86
VM
212 if (git_vector_init(&repo->memory_objects, 16, NULL) < GIT_SUCCESS) {
213 git_hashtable_free(repo->objects);
214 git_repository__refcache_free(&repo->references);
215 free(repo);
216 return NULL;
217 }
218
f335b42c 219 repo->gc_enabled = 1;
6fd195d7
VM
220 return repo;
221}
222
ec3c7a16
VM
223static int init_odb(git_repository *repo)
224{
225 return git_odb_open(&repo->db, repo->path_odb);
226}
227
228int git_repository_open3(git_repository **repo_out,
229 const char *git_dir,
230 git_odb *object_database,
231 const char *git_index_file,
232 const char *git_work_tree)
233{
234 git_repository *repo;
235 int error = GIT_SUCCESS;
236
237 assert(repo_out);
238
239 if (object_database == NULL)
240 return GIT_ERROR;
241
242 repo = repository_alloc();
243 if (repo == NULL)
244 return GIT_ENOMEM;
245
246 error = assign_repository_DIRs(repo,
247 git_dir,
248 NULL,
249 git_index_file,
d2d6912e 250 git_work_tree,
251 0);
ec3c7a16
VM
252
253 if (error < GIT_SUCCESS)
254 goto cleanup;
255
256 repo->db = object_database;
257
258 *repo_out = repo;
259 return GIT_SUCCESS;
260
261cleanup:
262 git_repository_free(repo);
263 return error;
264}
265
266
691aa968
VM
267int git_repository_open2(git_repository **repo_out,
268 const char *git_dir,
269 const char *git_object_directory,
270 const char *git_index_file,
271 const char *git_work_tree)
272{
273 git_repository *repo;
274 int error = GIT_SUCCESS;
275
276 assert(repo_out);
277
e52ed7a5 278 repo = repository_alloc();
691aa968
VM
279 if (repo == NULL)
280 return GIT_ENOMEM;
281
40c44d2f 282 error = assign_repository_DIRs(repo,
691aa968
VM
283 git_dir,
284 git_object_directory,
285 git_index_file,
d2d6912e 286 git_work_tree,
287 0);
691aa968 288
6f02c3ba 289 if (error < GIT_SUCCESS)
691aa968
VM
290 goto cleanup;
291
ec3c7a16 292 error = init_odb(repo);
6f02c3ba 293 if (error < GIT_SUCCESS)
691aa968
VM
294 goto cleanup;
295
296 *repo_out = repo;
297 return GIT_SUCCESS;
298
299cleanup:
300 git_repository_free(repo);
301 return error;
302}
303
d2d6912e 304static int repository_open_internal(git_repository **repo_out, const char *path, int is_repo_being_created)
6fd195d7
VM
305{
306 git_repository *repo;
1795f879
VM
307 int error = GIT_SUCCESS;
308
309 assert(repo_out && path);
6fd195d7 310
e52ed7a5 311 repo = repository_alloc();
6fd195d7 312 if (repo == NULL)
1795f879 313 return GIT_ENOMEM;
6fd195d7 314
d2d6912e 315 error = guess_repository_DIRs(repo, path, is_repo_being_created);
6f02c3ba 316 if (error < GIT_SUCCESS)
1795f879 317 goto cleanup;
3315782c 318
ec3c7a16 319 error = init_odb(repo);
6f02c3ba 320 if (error < GIT_SUCCESS)
1795f879
VM
321 goto cleanup;
322
323 *repo_out = repo;
324 return GIT_SUCCESS;
325
326cleanup:
327 git_repository_free(repo);
328 return error;
3315782c
VM
329}
330
d2d6912e 331int git_repository_open(git_repository **repo_out, const char *path)
332{
333 return repository_open_internal(repo_out, path, 0);
334}
335
584f49a5
VM
336static void repository_free(git_repository *repo)
337{
338 assert(repo);
339
340 free(repo->path_workdir);
341 free(repo->path_index);
342 free(repo->path_repository);
343 free(repo->path_odb);
344
345 git_hashtable_free(repo->objects);
346 git_vector_free(&repo->memory_objects);
347
348 git_repository__refcache_free(&repo->references);
349
350 if (repo->db != NULL)
351 git_odb_close(repo->db);
352
353 if (repo->index != NULL)
354 git_index_free(repo->index);
355
356 free(repo);
357}
358
359void git_repository_free__no_gc(git_repository *repo)
3315782c 360{
f49a2e49 361 git_object *object;
48c27f86
VM
362 const void *_unused;
363 unsigned int i;
3315782c 364
1f080e2d
VM
365 if (repo == NULL)
366 return;
1795f879 367
584f49a5
VM
368 GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,
369 object->repo = NULL;
370 object->refcount = 0;
371 );
372
373 for (i = 0; i < repo->memory_objects.length; ++i) {
374 object = git_vector_get(&repo->memory_objects, i);
375 object->repo = NULL;
376 object->refcount = 0;
377 }
378
379 repository_free(repo);
380}
381
382void git_repository_free(git_repository *repo)
383{
384 git_object *object;
385 const void *_unused;
386 unsigned int i;
387
388 if (repo == NULL)
389 return;
6fd195d7 390
f335b42c 391 repo->gc_enabled = 0;
48c27f86
VM
392
393 /* force free all the objects */
394 GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,
395 git_object__free(object);
396 );
397
398 for (i = 0; i < repo->memory_objects.length; ++i) {
399 object = git_vector_get(&repo->memory_objects, i);
400 git_object__free(object);
401 }
3315782c 402
584f49a5 403 repository_free(repo);
3315782c
VM
404}
405
c836c332 406int git_repository_index(git_index **index_out, git_repository *repo)
6fd195d7 407{
c836c332
VM
408 int error;
409
410 assert(index_out && repo);
411
6fd195d7 412 if (repo->index == NULL) {
c836c332
VM
413 error = git_index_open_inrepo(&repo->index, repo);
414 if (error < GIT_SUCCESS)
415 return error;
1795f879 416
c836c332 417 assert(repo->index != NULL);
6fd195d7
VM
418 }
419
c836c332
VM
420 *index_out = repo->index;
421 return GIT_SUCCESS;
6fd195d7
VM
422}
423
46f8566a
VM
424git_odb *git_repository_database(git_repository *repo)
425{
426 assert(repo);
427 return repo->db;
428}
429
fb3cd6bc 430static int repo_init_reinit(repo_init *results)
40c44d2f
VM
431{
432 /* TODO: reinit the repository */
4b8e27c8 433 results->has_been_reinit = 1;
434 return GIT_SUCCESS;
435}
436
d2d6912e 437static int repo_init_createhead(git_repository *repo)
e1f8cad0 438{
d2d6912e 439 git_reference *head_reference;
440 return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE);
441}
e1f8cad0 442
d2d6912e 443static int repo_init_check_head_existence(char * repository_path)
444{
445 char temp_path[GIT_PATH_MAX];
e1f8cad0 446
d2d6912e 447 git__joinpath(temp_path, repository_path, GIT_HEAD_FILE);
448 return gitfo_exists(temp_path);
e1f8cad0 449}
450
fb3cd6bc 451static int repo_init_structure(repo_init *results)
4b8e27c8 452{
a67a096a 453 const int mode = 0755; /* or 0777 ? */
4b8e27c8 454
40c44d2f 455 char temp_path[GIT_PATH_MAX];
40c44d2f 456 char *git_dir = results->path_repository;
4b8e27c8 457
a67a096a 458 if (gitfo_mkdir_recurs(git_dir, mode))
459 return GIT_ERROR;
460
8ea2c83b 461 /* Creates the '/objects/info/' directory */
874c3b6f
VM
462 git__joinpath(temp_path, git_dir, GIT_OBJECTS_INFO_DIR);
463 if (gitfo_mkdir_recurs(temp_path, mode) < GIT_SUCCESS)
a67a096a 464 return GIT_ERROR;
465
8ea2c83b 466 /* Creates the '/objects/pack/' directory */
874c3b6f 467 git__joinpath(temp_path, git_dir, GIT_OBJECTS_PACK_DIR);
a67a096a 468 if (gitfo_mkdir(temp_path, mode))
469 return GIT_ERROR;
470
1c2c7c0d 471 /* Creates the '/refs/heads/' directory */
874c3b6f 472 git__joinpath(temp_path, git_dir, GIT_REFS_HEADS_DIR);
8ea2c83b 473 if (gitfo_mkdir_recurs(temp_path, mode))
1c2c7c0d 474 return GIT_ERROR;
475
476 /* Creates the '/refs/tags/' directory */
874c3b6f 477 git__joinpath(temp_path, git_dir, GIT_REFS_TAGS_DIR);
1c2c7c0d 478 if (gitfo_mkdir(temp_path, mode))
479 return GIT_ERROR;
480
40c44d2f 481 /* TODO: what's left? templates? */
4b8e27c8 482
483 return GIT_SUCCESS;
484}
485
fb3cd6bc 486static int repo_init_find_dir(repo_init *results, const char* path)
4b8e27c8 487{
4b8e27c8 488 char temp_path[GIT_PATH_MAX];
9dd34b1e 489 int error = GIT_SUCCESS;
4b8e27c8 490
2e6fd09c 491 error = gitfo_prettify_dir_path(temp_path, path);
9dd34b1e 492 if (error < GIT_SUCCESS)
493 return error;
4b8e27c8 494
40c44d2f 495 if (!results->is_bare) {
874c3b6f 496 git__joinpath(temp_path, temp_path, GIT_DIR);
4b8e27c8 497 }
498
499 results->path_repository = git__strdup(temp_path);
8212e2d7
VM
500 if (results->path_repository == NULL)
501 return GIT_ENOMEM;
4b8e27c8 502
503 return GIT_SUCCESS;
504}
505
40c44d2f 506int git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare)
4b8e27c8 507{
4b8e27c8 508 int error = GIT_SUCCESS;
40c44d2f 509 repo_init results;
4b8e27c8 510
511 assert(repo_out && path);
512
40c44d2f 513 results.path_repository = NULL;
08190e2a 514 results.is_bare = is_bare;
4b8e27c8 515
40c44d2f 516 error = repo_init_find_dir(&results, path);
4b8e27c8 517 if (error < GIT_SUCCESS)
518 goto cleanup;
519
d2d6912e 520 if (!repo_init_check_head_existence(results.path_repository))
521 return repo_init_reinit(&results);
522
40c44d2f 523 error = repo_init_structure(&results);
4b8e27c8 524 if (error < GIT_SUCCESS)
525 goto cleanup;
526
d2d6912e 527 error = repository_open_internal(repo_out, results.path_repository, 1);
528 if (error < GIT_SUCCESS)
529 goto cleanup;
530
531 assert((*repo_out)->is_bare == is_bare);
532
533 error = repo_init_createhead(*repo_out);
4b8e27c8 534
535cleanup:
58fcfc26 536 free(results.path_repository);
4b8e27c8 537 return error;
40c44d2f 538}