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.
27 #include "git2/object.h"
30 #include "repository.h"
36 #define GIT_DIR "/.git/"
37 #define GIT_OBJECTS_DIR "objects/"
38 #define GIT_OBJECTS_INFO_DIR GIT_OBJECTS_DIR "info/"
39 #define GIT_OBJECTS_PACK_DIR GIT_OBJECTS_DIR "pack/"
40 #define GIT_REFS_DIR "refs/"
41 #define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/"
42 #define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/"
44 #define GIT_INDEX_FILE "index"
45 #define GIT_HEAD_FILE "HEAD"
47 #define GIT_SYMREF "ref: "
48 #define GIT_BRANCH_MASTER "master"
50 static const int OBJECT_TABLE_SIZE
= 32;
53 char *path_repository
;
54 unsigned is_bare
:1, has_been_reinit
:1;
60 * Callbacks for the ODB cache, implemented
63 uint32_t object_table_hash(const void *key
)
69 memcpy(&r
, id
->id
, sizeof(r
));
73 int object_table_hashkey(void *object
, const void *key
)
78 obj
= (git_object
*)object
;
81 return (git_oid_cmp(oid
, &obj
->id
) == 0);
86 * Git repository open methods
88 * Open a repository object from its path
90 static int assign_repository_DIRs(git_repository
*repo
,
92 const char *git_object_directory
,
93 const char *git_index_file
,
94 const char *git_work_tree
)
96 char path_aux
[GIT_PATH_MAX
];
101 if (git_dir
== NULL
|| gitfo_isdir(git_dir
) < GIT_SUCCESS
)
102 return GIT_ENOTFOUND
;
105 path_len
= strlen(git_dir
);
106 strcpy(path_aux
, git_dir
);
108 if (path_aux
[path_len
- 1] != '/') {
109 path_aux
[path_len
] = '/';
110 path_aux
[path_len
+ 1] = 0;
112 path_len
= path_len
+ 1;
115 repo
->path_repository
= git__strdup(path_aux
);
117 /* store GIT_OBJECT_DIRECTORY */
118 if (git_object_directory
== NULL
)
119 strcpy(path_aux
+ path_len
, GIT_OBJECTS_DIR
);
121 strcpy(path_aux
, git_object_directory
);
123 if (gitfo_isdir(path_aux
) < GIT_SUCCESS
)
124 return GIT_ENOTFOUND
;
126 repo
->path_odb
= git__strdup(path_aux
);
129 /* store GIT_INDEX_FILE */
130 if (git_index_file
== NULL
)
131 strcpy(path_aux
+ path_len
, GIT_INDEX_FILE
);
133 strcpy(path_aux
, git_index_file
);
135 if (gitfo_exists(path_aux
) < 0)
136 return GIT_ENOTFOUND
;
138 repo
->path_index
= git__strdup(path_aux
);
141 /* store GIT_WORK_TREE */
142 if (git_work_tree
== NULL
)
145 repo
->path_workdir
= git__strdup(git_work_tree
);
150 static int guess_repository_DIRs(git_repository
*repo
, const char *repository_path
)
152 char path_aux
[GIT_PATH_MAX
], *last_DIR
;
155 if (gitfo_isdir(repository_path
) < GIT_SUCCESS
)
156 return GIT_ENOTAREPO
;
158 path_len
= strlen(repository_path
);
159 strcpy(path_aux
, repository_path
);
161 if (path_aux
[path_len
- 1] != '/') {
162 path_aux
[path_len
] = '/';
163 path_aux
[path_len
+ 1] = 0;
165 path_len
= path_len
+ 1;
168 repo
->path_repository
= git__strdup(path_aux
);
170 /* objects database */
171 strcpy(path_aux
+ path_len
, GIT_OBJECTS_DIR
);
172 if (gitfo_isdir(path_aux
) < GIT_SUCCESS
)
173 return GIT_ENOTAREPO
;
174 repo
->path_odb
= git__strdup(path_aux
);
177 strcpy(path_aux
+ path_len
, GIT_HEAD_FILE
);
178 if (gitfo_exists(path_aux
) < 0)
179 return GIT_ENOTAREPO
;
181 path_aux
[path_len
] = 0;
183 last_DIR
= (path_aux
+ path_len
- 2);
185 while (*last_DIR
!= '/')
188 if (strcmp(last_DIR
, GIT_DIR
) == 0) {
192 strcpy(path_aux
+ path_len
, GIT_INDEX_FILE
);
193 repo
->path_index
= git__strdup(path_aux
);
197 repo
->path_workdir
= git__strdup(path_aux
);
201 repo
->path_workdir
= NULL
;
207 static git_repository
*repository_alloc()
209 git_repository
*repo
= git__malloc(sizeof(git_repository
));
213 memset(repo
, 0x0, sizeof(git_repository
));
215 repo
->objects
= git_hashtable_alloc(
218 object_table_hashkey
);
220 if (repo
->objects
== NULL
) {
228 int git_repository_open2(git_repository
**repo_out
,
230 const char *git_object_directory
,
231 const char *git_index_file
,
232 const char *git_work_tree
)
234 git_repository
*repo
;
235 int error
= GIT_SUCCESS
;
239 repo
= repository_alloc();
243 error
= assign_repository_DIRs(repo
,
245 git_object_directory
,
249 if (error
< GIT_SUCCESS
)
252 error
= git_odb_open(&repo
->db
, repo
->path_odb
);
253 if (error
< GIT_SUCCESS
)
260 git_repository_free(repo
);
264 int git_repository_open(git_repository
**repo_out
, const char *path
)
266 git_repository
*repo
;
267 int error
= GIT_SUCCESS
;
269 assert(repo_out
&& path
);
271 repo
= repository_alloc();
275 error
= guess_repository_DIRs(repo
, path
);
276 if (error
< GIT_SUCCESS
)
280 error
= git_odb_open(&repo
->db
, repo
->path_odb
);
281 if (error
< GIT_SUCCESS
)
288 git_repository_free(repo
);
292 void git_repository_free(git_repository
*repo
)
294 git_hashtable_iterator it
;
300 free(repo
->path_workdir
);
301 free(repo
->path_index
);
302 free(repo
->path_repository
);
303 free(repo
->path_odb
);
305 git_hashtable_iterator_init(repo
->objects
, &it
);
307 while ((object
= (git_object
*)
308 git_hashtable_iterator_next(&it
)) != NULL
)
309 git_object_free(object
);
311 git_hashtable_free(repo
->objects
);
313 if (repo
->db
!= NULL
)
314 git_odb_close(repo
->db
);
316 if (repo
->index
!= NULL
)
317 git_index_free(repo
->index
);
322 git_index
*git_repository_index(git_repository
*repo
)
324 if (repo
->index
== NULL
) {
325 if (git_index_open_inrepo(&repo
->index
, repo
) < GIT_SUCCESS
)
334 git_odb
*git_repository_database(git_repository
*repo
)
340 int git_repository_newobject(git_object
**object_out
, git_repository
*repo
, git_otype type
)
342 git_object
*object
= NULL
;
344 assert(object_out
&& repo
);
356 return GIT_EINVALIDTYPE
;
359 object
= git__malloc(git_object__size(type
));
364 memset(object
, 0x0, git_object__size(type
));
366 object
->in_memory
= 1;
367 object
->modified
= 1;
369 object
->source
.raw
.type
= type
;
371 *object_out
= object
;
375 int git_repository_lookup(git_object
**object_out
, git_repository
*repo
, const git_oid
*id
, git_otype type
)
377 git_object
*object
= NULL
;
379 int error
= GIT_SUCCESS
;
381 assert(repo
&& object_out
&& id
);
383 object
= git_hashtable_lookup(repo
->objects
, id
);
384 if (object
!= NULL
) {
385 *object_out
= object
;
389 error
= git_odb_read(&obj_file
, repo
->db
, id
);
390 if (error
< GIT_SUCCESS
)
393 if (type
!= GIT_OBJ_ANY
&& type
!= obj_file
.type
) {
394 git_rawobj_close(&obj_file
);
395 return GIT_EINVALIDTYPE
;
398 type
= obj_file
.type
;
400 object
= git__malloc(git_object__size(type
));
405 memset(object
, 0x0, git_object__size(type
));
407 /* Initialize parent object */
408 git_oid_cpy(&object
->id
, id
);
410 memcpy(&object
->source
.raw
, &obj_file
, sizeof(git_rawobj
));
411 object
->source
.open
= 1;
416 error
= git_commit__parse((git_commit
*)object
);
420 error
= git_tree__parse((git_tree
*)object
);
424 error
= git_tag__parse((git_tag
*)object
);
428 error
= git_blob__parse((git_blob
*)object
);
435 if (error
< GIT_SUCCESS
) {
436 git_object_free(object
);
440 git_object__source_close(object
);
441 git_hashtable_insert(repo
->objects
, &object
->id
, object
);
443 *object_out
= object
;
447 static int repo_init_reinit(repo_init
*results
)
449 /* TODO: reinit the repository */
450 results
->has_been_reinit
= 1;
454 static int repo_init_createhead(const char *head_path
)
457 int error
= GIT_SUCCESS
;
458 char head_symlink
[50];
461 len
= sprintf(head_symlink
, "%s %s%s\n", GIT_SYMREF
, GIT_REFS_HEADS_DIR
, GIT_BRANCH_MASTER
);
463 if ((fd
= gitfo_creat(head_path
, S_IREAD
| S_IWRITE
)) < GIT_SUCCESS
)
466 error
= gitfo_write(fd
, (void*)head_symlink
, strlen(head_symlink
));
472 static int repo_init_structure(repo_init
*results
)
474 const int mode
= 0755; /* or 0777 ? */
476 char temp_path
[GIT_PATH_MAX
];
478 char *git_dir
= results
->path_repository
;
480 if (gitfo_mkdir_recurs(git_dir
, mode
))
483 path_len
= strlen(git_dir
);
484 strcpy(temp_path
, git_dir
);
486 /* Does HEAD file already exist ? */
487 strcpy(temp_path
+ path_len
, GIT_HEAD_FILE
);
489 if (gitfo_exists(temp_path
) == GIT_SUCCESS
)
490 return repo_init_reinit(results
);
492 if (repo_init_createhead(temp_path
) < GIT_SUCCESS
)
495 /* Creates the '/objects/info/' directory */
496 strcpy(temp_path
+ path_len
, GIT_OBJECTS_INFO_DIR
);
497 if (gitfo_mkdir_recurs(temp_path
, mode
))
500 /* Creates the '/objects/pack/' directory */
501 strcpy(temp_path
+ path_len
, GIT_OBJECTS_PACK_DIR
);
502 if (gitfo_mkdir(temp_path
, mode
))
505 /* Creates the '/refs/heads/' directory */
506 strcpy(temp_path
+ path_len
, GIT_REFS_HEADS_DIR
);
507 if (gitfo_mkdir_recurs(temp_path
, mode
))
510 /* Creates the '/refs/tags/' directory */
511 strcpy(temp_path
+ path_len
, GIT_REFS_TAGS_DIR
);
512 if (gitfo_mkdir(temp_path
, mode
))
515 /* TODO: what's left? templates? */
520 static int repo_init_find_dir(repo_init
*results
, const char* path
)
522 const int MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH
= 66;
524 char temp_path
[GIT_PATH_MAX
];
527 path_len
= strlen(path
);
528 strcpy(temp_path
, path
);
530 /* Ensure path has a trailing slash */
531 if (temp_path
[path_len
- 1] != '/') {
532 temp_path
[path_len
] = '/';
533 temp_path
[path_len
+ 1] = 0;
535 path_len
= path_len
+ 1;
538 if (!results
->is_bare
) {
539 strcpy(temp_path
+ path_len
- 1, GIT_DIR
);
540 path_len
= path_len
+ strlen(GIT_DIR
) - 1; /* Skip the leading slash from the constant */
543 if (path_len
>= GIT_PATH_MAX
- MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH
)
544 return GIT_ENOTAREPO
;
546 results
->path_repository
= git__strdup(temp_path
);
551 int git_repository_init(git_repository
**repo_out
, const char *path
, unsigned is_bare
)
553 int error
= GIT_SUCCESS
;
556 assert(repo_out
&& path
);
558 results
.path_repository
= NULL
;
559 results
.is_bare
= is_bare
;
561 error
= repo_init_find_dir(&results
, path
);
562 if (error
< GIT_SUCCESS
)
565 error
= repo_init_structure(&results
);
566 if (error
< GIT_SUCCESS
)
569 error
= git_repository_open(repo_out
, results
.path_repository
);
572 free(results
.path_repository
);