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.
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.)
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.
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.
28 #include "repository.h"
34 static const int default_table_size
= 32;
35 static const double max_load_factor
= 0.65;
37 static const int OBJECT_BASE_SIZE
= 4096;
39 static const size_t object_sizes
[] = {
48 uint32_t git__objtable_hash(const void *key
)
54 memcpy(&r
, id
->id
, sizeof(r
));
58 int git__objtable_haskey(void *object
, const void *key
)
63 obj
= (git_object
*)object
;
66 return (git_oid_cmp(oid
, &obj
->id
) == 0);
69 static int parse_repository_folders(git_repository
*repo
, const char *repository_path
)
71 char path_aux
[GIT_PATH_MAX
], *last_folder
;
74 if (gitfo_isdir(repository_path
) < 0)
77 path_len
= strlen(repository_path
);
78 strcpy(path_aux
, repository_path
);
80 if (path_aux
[path_len
- 1] != '/') {
81 path_aux
[path_len
] = '/';
82 path_aux
[path_len
+ 1] = 0;
84 path_len
= path_len
+ 1;
87 repo
->path_repository
= git__strdup(path_aux
);
89 /* objects database */
90 strcpy(path_aux
+ path_len
, "objects/");
91 if (gitfo_isdir(path_aux
) < 0)
93 repo
->path_odb
= git__strdup(path_aux
);
96 strcpy(path_aux
+ path_len
, "HEAD");
97 if (gitfo_exists(path_aux
) < 0)
100 path_aux
[path_len
] = 0;
102 last_folder
= (path_aux
+ path_len
- 2);
104 while (*last_folder
!= '/')
107 if (strcmp(last_folder
, "/.git/") == 0) {
111 strcpy(path_aux
+ path_len
, "index");
112 repo
->path_index
= git__strdup(path_aux
);
115 *(last_folder
+ 1) = 0;
116 repo
->path_workdir
= git__strdup(path_aux
);
120 repo
->path_workdir
= NULL
;
126 git_repository
*git_repository__alloc()
128 git_repository
*repo
= git__malloc(sizeof(git_repository
));
132 memset(repo
, 0x0, sizeof(git_repository
));
134 repo
->objects
= git_hashtable_alloc(
137 git__objtable_haskey
);
139 if (repo
->objects
== NULL
) {
147 int git_repository_open(git_repository
**repo_out
, const char *path
)
149 git_repository
*repo
;
150 int error
= GIT_SUCCESS
;
152 assert(repo_out
&& path
);
154 repo
= git_repository__alloc();
158 error
= parse_repository_folders(repo
, path
);
162 error
= git_odb_open(&repo
->db
, repo
->path_odb
);
170 git_repository_free(repo
);
174 void git_repository_free(git_repository
*repo
)
176 git_hashtable_iterator it
;
181 free(repo
->path_workdir
);
182 free(repo
->path_index
);
183 free(repo
->path_repository
);
184 free(repo
->path_odb
);
186 git_hashtable_iterator_init(repo
->objects
, &it
);
188 while ((object
= (git_object
*)
189 git_hashtable_iterator_next(&it
)) != NULL
)
190 git_object_free(object
);
192 git_hashtable_free(repo
->objects
);
193 git_odb_close(repo
->db
);
194 git_index_free(repo
->index
);
198 git_index
*git_repository_index(git_repository
*repo
)
200 if (repo
->index
== NULL
) {
201 if (git_index_open_inrepo(&repo
->index
, repo
) < 0)
210 static int source_resize(git_odb_source
*src
)
212 size_t write_offset
, new_size
;
215 write_offset
= (size_t)((char *)src
->write_ptr
- (char *)src
->raw
.data
);
217 new_size
= src
->raw
.len
* 2;
218 if ((new_data
= git__malloc(new_size
)) == NULL
)
221 memcpy(new_data
, src
->raw
.data
, src
->written_bytes
);
224 src
->raw
.data
= new_data
;
225 src
->raw
.len
= new_size
;
226 src
->write_ptr
= (char *)new_data
+ write_offset
;
231 int git__source_printf(git_odb_source
*source
, const char *format
, ...)
234 int len
, did_resize
= 0;
236 assert(source
->open
&& source
->write_ptr
);
238 va_start(arglist
, format
);
240 len
= vsnprintf(source
->write_ptr
, source
->raw
.len
- source
->written_bytes
, format
, arglist
);
242 while (source
->written_bytes
+ len
>= source
->raw
.len
) {
243 if (source_resize(source
) < 0)
250 vsnprintf(source
->write_ptr
, source
->raw
.len
- source
->written_bytes
, format
, arglist
);
252 source
->write_ptr
= (char *)source
->write_ptr
+ len
;
253 source
->written_bytes
+= len
;
258 int git__source_write(git_odb_source
*source
, const void *bytes
, size_t len
)
262 assert(source
->open
&& source
->write_ptr
);
264 while (source
->written_bytes
+ len
>= source
->raw
.len
) {
265 if (source_resize(source
) < 0)
269 memcpy(source
->write_ptr
, bytes
, len
);
270 source
->write_ptr
= (char *)source
->write_ptr
+ len
;
271 source
->written_bytes
+= len
;
276 static void prepare_write(git_object
*object
)
278 if (object
->source
.write_ptr
!= NULL
|| object
->source
.open
)
279 git_object__source_close(object
);
281 /* TODO: proper size calculation */
282 object
->source
.raw
.data
= git__malloc(OBJECT_BASE_SIZE
);
283 object
->source
.raw
.len
= OBJECT_BASE_SIZE
;
285 object
->source
.write_ptr
= object
->source
.raw
.data
;
286 object
->source
.written_bytes
= 0;
288 object
->source
.open
= 1;
291 static int write_back(git_object
*object
)
298 assert(object
->source
.open
);
299 assert(object
->modified
);
301 object
->source
.raw
.len
= object
->source
.written_bytes
;
303 if ((error
= git_odb_write(&new_id
, object
->repo
->db
, &object
->source
.raw
)) < 0)
306 if (!object
->in_memory
)
307 git_hashtable_remove(object
->repo
->objects
, &object
->id
);
309 git_oid_cpy(&object
->id
, &new_id
);
310 git_hashtable_insert(object
->repo
->objects
, &object
->id
, object
);
312 object
->source
.write_ptr
= NULL
;
313 object
->source
.written_bytes
= 0;
315 object
->modified
= 0;
316 object
->in_memory
= 0;
318 git_object__source_close(object
);
322 int git_object__source_open(git_object
*object
)
326 assert(object
&& !object
->in_memory
);
328 if (object
->source
.open
)
329 git_object__source_close(object
);
331 error
= git_odb_read(&object
->source
.raw
, object
->repo
->db
, &object
->id
);
335 object
->source
.open
= 1;
339 void git_object__source_close(git_object
*object
)
343 if (object
->source
.open
) {
344 git_obj_close(&object
->source
.raw
);
345 object
->source
.open
= 0;
349 int git_object_write(git_object
*object
)
352 git_odb_source
*source
;
356 if (object
->modified
== 0)
359 prepare_write(object
);
360 source
= &object
->source
;
362 switch (source
->raw
.type
) {
364 error
= git_commit__writeback((git_commit
*)object
, source
);
368 error
= git_tree__writeback((git_tree
*)object
, source
);
372 error
= git_tag__writeback((git_tag
*)object
, source
);
376 error
= git_blob__writeback((git_blob
*)object
, source
);
385 git_object__source_close(object
);
389 return write_back(object
);
392 void git_object_free(git_object
*object
)
396 git_object__source_close(object
);
397 git_hashtable_remove(object
->repo
->objects
, &object
->id
);
399 switch (object
->source
.raw
.type
) {
401 git_commit__free((git_commit
*)object
);
405 git_tree__free((git_tree
*)object
);
409 git_tag__free((git_tag
*)object
);
413 git_blob__free((git_blob
*)object
);
422 git_odb
*git_repository_database(git_repository
*repo
)
428 const git_oid
*git_object_id(git_object
*obj
)
438 git_otype
git_object_type(git_object
*obj
)
441 return obj
->source
.raw
.type
;
444 git_repository
*git_object_owner(git_object
*obj
)
450 int git_repository_newobject(git_object
**object_out
, git_repository
*repo
, git_otype type
)
452 git_object
*object
= NULL
;
454 assert(object_out
&& repo
);
466 return GIT_EINVALIDTYPE
;
469 object
= git__malloc(object_sizes
[type
]);
474 memset(object
, 0x0, object_sizes
[type
]);
476 object
->in_memory
= 1;
477 object
->modified
= 1;
479 object
->source
.raw
.type
= type
;
481 *object_out
= object
;
485 int git_repository_lookup(git_object
**object_out
, git_repository
*repo
, const git_oid
*id
, git_otype type
)
487 git_object
*object
= NULL
;
491 assert(repo
&& object_out
&& id
);
493 object
= git_hashtable_lookup(repo
->objects
, id
);
494 if (object
!= NULL
) {
495 *object_out
= object
;
499 error
= git_odb_read(&obj_file
, repo
->db
, id
);
503 if (type
!= GIT_OBJ_ANY
&& type
!= obj_file
.type
)
504 return GIT_EINVALIDTYPE
;
506 type
= obj_file
.type
;
508 object
= git__malloc(object_sizes
[type
]);
513 memset(object
, 0x0, object_sizes
[type
]);
515 /* Initialize parent object */
516 git_oid_cpy(&object
->id
, id
);
518 memcpy(&object
->source
.raw
, &obj_file
, sizeof(git_rawobj
));
519 object
->source
.open
= 1;
524 error
= git_commit__parse((git_commit
*)object
);
528 error
= git_tree__parse((git_tree
*)object
);
532 error
= git_tag__parse((git_tag
*)object
);
536 error
= git_blob__parse((git_blob
*)object
);
544 git_object_free(object
);
548 git_object__source_close(object
);
549 git_hashtable_insert(repo
->objects
, &object
->id
, object
);
551 *object_out
= object
;
555 #define GIT_NEWOBJECT_TEMPLATE(obj, tp) \
556 int git_##obj##_new(git_##obj **o, git_repository *repo) {\
557 return git_repository_newobject((git_object **)o, repo, GIT_OBJ_##tp); } \
558 int git_##obj##_lookup(git_##obj **o, git_repository *repo, const git_oid *id) { \
559 return git_repository_lookup((git_object **)o, repo, id, GIT_OBJ_##tp); }
561 GIT_NEWOBJECT_TEMPLATE(commit
, COMMIT
)
562 GIT_NEWOBJECT_TEMPLATE(tag
, TAG
)
563 GIT_NEWOBJECT_TEMPLATE(tree
, TREE
)
564 GIT_NEWOBJECT_TEMPLATE(blob
, BLOB
)