]> git.proxmox.com Git - libgit2.git/blame - src/repository.c
accessor for index entry count
[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
VM
26
27#include "common.h"
28#include "repository.h"
29#include "commit.h"
30#include "tag.h"
6fd195d7 31#include "fileops.h"
3315782c
VM
32
33static const int default_table_size = 32;
34static const double max_load_factor = 0.65;
35
58519018
VM
36static const int OBJECT_BASE_SIZE = 4096;
37
d45b4a9a
VM
38static const size_t object_sizes[] = {
39 0,
40 sizeof(git_commit),
41 sizeof(git_tree),
42 sizeof(git_object), /* TODO: sizeof(git_blob) */
43 sizeof(git_tag)
44};
45
46
6fd195d7 47uint32_t git__objtable_hash(const void *key)
3315782c
VM
48{
49 uint32_t r;
50 git_oid *id;
51
52 id = (git_oid *)key;
53 memcpy(&r, id->id, sizeof(r));
54 return r;
55}
56
6fd195d7 57int git__objtable_haskey(void *object, const void *key)
3315782c 58{
f49a2e49 59 git_object *obj;
3315782c
VM
60 git_oid *oid;
61
f49a2e49 62 obj = (git_object *)object;
3315782c
VM
63 oid = (git_oid *)key;
64
65 return (git_oid_cmp(oid, &obj->id) == 0);
66}
67
6fd195d7
VM
68static int parse_repository_folders(git_repository *repo, const char *repository_path)
69{
70 char path_aux[GIT_PATH_MAX];
71 int path_len, i;
72
73 if (gitfo_isdir(repository_path) < 0)
1795f879 74 return GIT_ENOTAREPO;
6fd195d7
VM
75
76 path_len = strlen(repository_path);
77 strcpy(path_aux, repository_path);
78
79 if (path_aux[path_len - 1] != '/') {
80 path_aux[path_len] = '/';
81 path_aux[path_len + 1] = 0;
82
83 path_len = path_len + 1;
84 }
85
86 repo->path_repository = git__strdup(path_aux);
87
88 /* objects database */
89 strcpy(path_aux + path_len, "objects/");
90 if (gitfo_isdir(path_aux) < 0)
1795f879 91 return GIT_ENOTAREPO;
6fd195d7
VM
92 repo->path_odb = git__strdup(path_aux);
93
6fd195d7
VM
94 /* HEAD file */
95 strcpy(path_aux + path_len, "HEAD");
96 if (gitfo_exists(path_aux) < 0)
1795f879 97 return GIT_ENOTAREPO;
6fd195d7
VM
98
99 i = path_len - 2;
100 while (path_aux[i] != '/')
101 i--;
102
103 if (strcmp(path_aux, "/.git/") == 0) {
104 repo->is_bare = 0;
105
106 path_aux[i + 1] = 0;
107 repo->path_workdir = git__strdup(path_aux);
108
1544bc31
DB
109 /* index file */
110 strcpy(path_aux + path_len, "index");
111 if (gitfo_exists(path_aux) < 0)
1795f879 112 return GIT_ENOTAREPO;
1544bc31
DB
113 repo->path_index = git__strdup(path_aux);
114
6fd195d7
VM
115 } else {
116 repo->is_bare = 1;
117 repo->path_workdir = NULL;
118 }
119
120 return GIT_SUCCESS;
121}
122
123git_repository *git_repository__alloc()
3315782c
VM
124{
125 git_repository *repo = git__malloc(sizeof(git_repository));
126 if (!repo)
127 return NULL;
128
129 memset(repo, 0x0, sizeof(git_repository));
130
131 repo->objects = git_hashtable_alloc(
132 default_table_size,
6fd195d7
VM
133 git__objtable_hash,
134 git__objtable_haskey);
3315782c
VM
135
136 if (repo->objects == NULL) {
137 free(repo);
138 return NULL;
139 }
140
6fd195d7
VM
141 return repo;
142}
143
1795f879 144int git_repository_open(git_repository **repo_out, const char *path)
6fd195d7
VM
145{
146 git_repository *repo;
1795f879
VM
147 int error = GIT_SUCCESS;
148
149 assert(repo_out && path);
6fd195d7
VM
150
151 repo = git_repository__alloc();
152 if (repo == NULL)
1795f879 153 return GIT_ENOMEM;
6fd195d7 154
1795f879
VM
155 error = parse_repository_folders(repo, path);
156 if (error < 0)
157 goto cleanup;
3315782c 158
1795f879
VM
159 error = git_odb_open(&repo->db, repo->path_odb);
160 if (error < 0)
161 goto cleanup;
162
163 *repo_out = repo;
164 return GIT_SUCCESS;
165
166cleanup:
167 git_repository_free(repo);
168 return error;
3315782c
VM
169}
170
171void git_repository_free(git_repository *repo)
172{
173 git_hashtable_iterator it;
f49a2e49 174 git_object *object;
3315782c 175
1795f879
VM
176 assert(repo);
177
6fd195d7
VM
178 free(repo->path_workdir);
179 free(repo->path_index);
180 free(repo->path_repository);
181 free(repo->path_odb);
182
3315782c
VM
183 git_hashtable_iterator_init(repo->objects, &it);
184
f49a2e49 185 while ((object = (git_object *)
9c9f4fc1 186 git_hashtable_iterator_next(&it)) != NULL)
f49a2e49 187 git_object_free(object);
3315782c
VM
188
189 git_hashtable_free(repo->objects);
6fd195d7
VM
190 git_odb_close(repo->db);
191 git_index_free(repo->index);
3315782c
VM
192 free(repo);
193}
194
6fd195d7
VM
195git_index *git_repository_index(git_repository *repo)
196{
197 if (repo->index == NULL) {
1795f879
VM
198 if (git_index_open(&repo->index, repo->path_index, repo->path_workdir) < 0)
199 return NULL;
200
6fd195d7
VM
201 assert(repo->index && repo->index->on_disk);
202 }
203
204 return repo->index;
205}
206
e802d8cc
VM
207static int source_resize(git_odb_source *src)
208{
209 size_t write_offset, new_size;
210 void *new_data;
211
212 write_offset = src->write_ptr - src->raw.data;
213
214 new_size = src->raw.len * 2;
215 if ((new_data = git__malloc(new_size)) == NULL)
216 return GIT_ENOMEM;
217
218 memcpy(new_data, src->raw.data, src->written_bytes);
219 free(src->raw.data);
220
221 src->raw.data = new_data;
222 src->raw.len = new_size;
223 src->write_ptr = new_data + write_offset;
224
225 return GIT_SUCCESS;
226}
227
228int git__source_printf(git_odb_source *source, const char *format, ...)
229{
230 va_list arglist;
231 int len, did_resize = 0;
232
1795f879 233 assert(source->open && source->write_ptr);
e802d8cc
VM
234
235 va_start(arglist, format);
236
237 len = vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);
238
239 while (source->written_bytes + len >= source->raw.len) {
240 if (source_resize(source) < 0)
241 return GIT_ENOMEM;
242
243 did_resize = 1;
244 }
245
246 if (did_resize)
247 vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);
248
249 source->write_ptr += len;
250 source->written_bytes += len;
251
252 return GIT_SUCCESS;
253}
254
255int git__source_write(git_odb_source *source, const void *bytes, size_t len)
256{
257 assert(source);
258
1795f879 259 assert(source->open && source->write_ptr);
e802d8cc
VM
260
261 while (source->written_bytes + len >= source->raw.len) {
262 if (source_resize(source) < 0)
263 return GIT_ENOMEM;
264 }
265
266 memcpy(source->write_ptr, bytes, len);
267 source->write_ptr += len;
268 source->written_bytes += len;
269
270 return GIT_SUCCESS;
271}
272
d45b4a9a 273static void prepare_write(git_object *object)
a7a7ddbe 274{
f49a2e49
VM
275 if (object->source.write_ptr != NULL || object->source.open)
276 git_object__source_close(object);
a7a7ddbe
VM
277
278 /* TODO: proper size calculation */
58519018
VM
279 object->source.raw.data = git__malloc(OBJECT_BASE_SIZE);
280 object->source.raw.len = OBJECT_BASE_SIZE;
a7a7ddbe 281
f49a2e49
VM
282 object->source.write_ptr = object->source.raw.data;
283 object->source.written_bytes = 0;
a7a7ddbe 284
f49a2e49 285 object->source.open = 1;
a7a7ddbe
VM
286}
287
d45b4a9a 288static int write_back(git_object *object)
a7a7ddbe
VM
289{
290 int error;
291 git_oid new_id;
292
293 assert(object);
294
58519018 295 assert(object->source.open);
d45b4a9a 296 assert(object->modified);
58519018 297
f49a2e49 298 object->source.raw.len = object->source.written_bytes;
a7a7ddbe 299
f49a2e49 300 git_obj_hash(&new_id, &object->source.raw);
a7a7ddbe 301
f49a2e49 302 if ((error = git_odb_write(&new_id, object->repo->db, &object->source.raw)) < 0)
a7a7ddbe
VM
303 return error;
304
d45b4a9a
VM
305 if (!object->in_memory)
306 git_hashtable_remove(object->repo->objects, &object->id);
307
a7a7ddbe
VM
308 git_oid_cpy(&object->id, &new_id);
309 git_hashtable_insert(object->repo->objects, &object->id, object);
310
f49a2e49
VM
311 object->source.write_ptr = NULL;
312 object->source.written_bytes = 0;
a7a7ddbe 313
0c3596f1 314 object->modified = 0;
d45b4a9a 315 object->in_memory = 0;
0c3596f1 316
f49a2e49 317 git_object__source_close(object);
a7a7ddbe
VM
318 return GIT_SUCCESS;
319}
320
f49a2e49 321int git_object__source_open(git_object *object)
f2408cc2
VM
322{
323 int error;
324
d45b4a9a 325 assert(object && !object->in_memory);
a7a7ddbe 326
d45b4a9a 327 if (object->source.open)
f49a2e49 328 git_object__source_close(object);
a7a7ddbe 329
f49a2e49 330 error = git_odb_read(&object->source.raw, object->repo->db, &object->id);
f2408cc2
VM
331 if (error < 0)
332 return error;
333
f49a2e49 334 object->source.open = 1;
f2408cc2
VM
335 return GIT_SUCCESS;
336}
337
f49a2e49 338void git_object__source_close(git_object *object)
f2408cc2 339{
a7a7ddbe
VM
340 assert(object);
341
58519018 342 if (object->source.open) {
f49a2e49
VM
343 git_obj_close(&object->source.raw);
344 object->source.open = 0;
f2408cc2
VM
345 }
346}
347
0c3596f1
VM
348int git_object_write(git_object *object)
349{
350 int error;
351 git_odb_source *source;
352
353 assert(object);
354
355 if (object->modified == 0)
356 return GIT_SUCCESS;
357
d45b4a9a 358 prepare_write(object);
0c3596f1
VM
359 source = &object->source;
360
361 switch (source->raw.type) {
362 case GIT_OBJ_COMMIT:
363 error = git_commit__writeback((git_commit *)object, source);
364 break;
365
366 case GIT_OBJ_TREE:
2a884588
VM
367 error = git_tree__writeback((git_tree *)object, source);
368 break;
369
0c3596f1 370 case GIT_OBJ_TAG:
ec25391d
VM
371 error = git_tag__writeback((git_tag *)object, source);
372 break;
373
0c3596f1
VM
374 default:
375 error = GIT_ERROR;
d45b4a9a 376 break;
0c3596f1
VM
377 }
378
379 if (error < 0) {
380 git_object__source_close(object);
381 return error;
382 }
d45b4a9a
VM
383
384 return write_back(object);
0c3596f1
VM
385}
386
f49a2e49 387void git_object_free(git_object *object)
9c9f4fc1 388{
a7a7ddbe
VM
389 assert(object);
390
58519018 391 git_object__source_close(object);
9c9f4fc1 392 git_hashtable_remove(object->repo->objects, &object->id);
9c9f4fc1 393
f49a2e49 394 switch (object->source.raw.type) {
9c9f4fc1
VM
395 case GIT_OBJ_COMMIT:
396 git_commit__free((git_commit *)object);
397 break;
398
399 case GIT_OBJ_TREE:
400 git_tree__free((git_tree *)object);
401 break;
402
403 case GIT_OBJ_TAG:
404 git_tag__free((git_tag *)object);
405 break;
406
407 default:
408 free(object);
409 break;
410 }
411}
412
46f8566a
VM
413git_odb *git_repository_database(git_repository *repo)
414{
415 assert(repo);
416 return repo->db;
417}
418
f49a2e49 419const git_oid *git_object_id(git_object *obj)
46f8566a
VM
420{
421 assert(obj);
d45b4a9a
VM
422
423 if (obj->in_memory)
424 return NULL;
425
46f8566a
VM
426 return &obj->id;
427}
428
f49a2e49 429git_otype git_object_type(git_object *obj)
46f8566a
VM
430{
431 assert(obj);
f49a2e49 432 return obj->source.raw.type;
46f8566a
VM
433}
434
a13bc8e7
VM
435git_repository *git_object_owner(git_object *obj)
436{
437 assert(obj);
438 return obj->repo;
439}
440
1795f879 441int git_repository_newobject(git_object **object_out, git_repository *repo, git_otype type)
3315782c 442{
d45b4a9a 443 git_object *object = NULL;
f2408cc2 444
1795f879
VM
445 assert(object_out && repo);
446
447 *object_out = NULL;
448
d45b4a9a
VM
449 switch (type) {
450 case GIT_OBJ_COMMIT:
451 case GIT_OBJ_TAG:
452 case GIT_OBJ_TREE:
453 case GIT_OBJ_BLOB:
454 break;
455
456 default:
1795f879 457 return GIT_EINVALIDTYPE;
d45b4a9a
VM
458 }
459
460 object = git__malloc(object_sizes[type]);
461
462 if (object == NULL)
1795f879 463 return GIT_ENOMEM;
d45b4a9a
VM
464
465 memset(object, 0x0, object_sizes[type]);
466 object->repo = repo;
467 object->in_memory = 1;
468 object->modified = 1;
469
470 object->source.raw.type = type;
471
1795f879
VM
472 *object_out = object;
473 return GIT_SUCCESS;
d45b4a9a
VM
474}
475
1795f879 476int git_repository_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type)
d45b4a9a 477{
f49a2e49
VM
478 git_object *object = NULL;
479 git_rawobj obj_file;
58519018 480 int error = 0;
3315782c 481
1795f879 482 assert(repo && object_out && id);
3315782c
VM
483
484 object = git_hashtable_lookup(repo->objects, id);
1795f879
VM
485 if (object != NULL) {
486 *object_out = object;
487 return GIT_SUCCESS;
488 }
3315782c 489
1795f879
VM
490 error = git_odb_read(&obj_file, repo->db, id);
491 if (error < 0)
492 return error;
3315782c 493
f2408cc2 494 if (type != GIT_OBJ_ANY && type != obj_file.type)
1795f879 495 return GIT_EINVALIDTYPE;
f2408cc2
VM
496
497 type = obj_file.type;
498
499 object = git__malloc(object_sizes[type]);
3315782c
VM
500
501 if (object == NULL)
1795f879 502 return GIT_ENOMEM;
3315782c 503
f2408cc2 504 memset(object, 0x0, object_sizes[type]);
3315782c
VM
505
506 /* Initialize parent object */
507 git_oid_cpy(&object->id, id);
508 object->repo = repo;
f49a2e49 509 memcpy(&object->source.raw, &obj_file, sizeof(git_rawobj));
58519018 510 object->source.open = 1;
3315782c 511
f2408cc2 512 switch (type) {
3315782c 513
f2408cc2 514 case GIT_OBJ_COMMIT:
58519018 515 error = git_commit__parse((git_commit *)object);
f2408cc2
VM
516 break;
517
518 case GIT_OBJ_TREE:
58519018 519 error = git_tree__parse((git_tree *)object);
f2408cc2
VM
520 break;
521
522 case GIT_OBJ_TAG:
58519018 523 error = git_tag__parse((git_tag *)object);
f2408cc2
VM
524 break;
525
58519018 526 case GIT_OBJ_BLOB:
f2408cc2
VM
527 default:
528 /* blobs get no parsing */
529 break;
530 }
531
58519018
VM
532 if (error < 0) {
533 git_object_free(object);
1795f879 534 return error;
58519018 535 }
f2408cc2 536
58519018 537 git_object__source_close(object);
f2408cc2 538 git_hashtable_insert(repo->objects, &object->id, object);
1795f879
VM
539
540 *object_out = object;
541 return GIT_SUCCESS;
3315782c 542}
1795f879
VM
543
544#define GIT_NEWOBJECT_TEMPLATE(obj, tp) \
545 int git_##obj##_new(git_##obj **o, git_repository *repo) {\
546 return git_repository_newobject((git_object **)o, repo, GIT_OBJ_##tp); } \
547 int git_##obj##_lookup(git_##obj **o, git_repository *repo, const git_oid *id) { \
548 return git_repository_lookup((git_object **)o, repo, id, GIT_OBJ_##tp); }
549
550GIT_NEWOBJECT_TEMPLATE(commit, COMMIT)
551GIT_NEWOBJECT_TEMPLATE(tag, TAG)
552GIT_NEWOBJECT_TEMPLATE(tree, TREE)
553
554