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"
38 #define GIT_OBJECTS_INFO_DIR GIT_OBJECTS_DIR "info/"
39 #define GIT_OBJECTS_PACK_DIR GIT_OBJECTS_DIR "pack/"
41 #define GIT_BRANCH_MASTER "master"
44 char *path_repository
;
45 unsigned is_bare
:1, has_been_reinit
:1;
49 * Git repository open methods
51 * Open a repository object from its path
53 static int assign_repository_dirs(
56 const char *git_object_directory
,
57 const char *git_index_file
,
58 const char *git_work_tree
)
60 char path_aux
[GIT_PATH_MAX
];
61 int error
= GIT_SUCCESS
;
66 return git__throw(GIT_ENOTFOUND
, "Failed to open repository. Git dir not found");
68 error
= gitfo_prettify_dir_path(path_aux
, sizeof(path_aux
), git_dir
);
69 if (error
< GIT_SUCCESS
)
70 return git__rethrow(error
, "Failed to open repository");
73 repo
->path_repository
= git__strdup(path_aux
);
74 if (repo
->path_repository
== NULL
)
77 /* path to GIT_OBJECT_DIRECTORY */
78 if (git_object_directory
== NULL
)
79 git__joinpath(path_aux
, repo
->path_repository
, GIT_OBJECTS_DIR
);
81 error
= gitfo_prettify_dir_path(path_aux
, sizeof(path_aux
), git_object_directory
);
82 if (error
< GIT_SUCCESS
)
83 return git__rethrow(error
, "Failed to open repository");
86 /* Store GIT_OBJECT_DIRECTORY */
87 repo
->path_odb
= git__strdup(path_aux
);
88 if (repo
->path_odb
== NULL
)
91 /* path to GIT_WORK_TREE */
92 if (git_work_tree
== NULL
)
95 error
= gitfo_prettify_dir_path(path_aux
, sizeof(path_aux
), git_work_tree
);
96 if (error
< GIT_SUCCESS
)
97 return git__rethrow(error
, "Failed to open repository");
99 /* Store GIT_WORK_TREE */
100 repo
->path_workdir
= git__strdup(path_aux
);
101 if (repo
->path_workdir
== NULL
)
104 /* Path to GIT_INDEX_FILE */
105 if (git_index_file
== NULL
)
106 git__joinpath(path_aux
, repo
->path_repository
, GIT_INDEX_FILE
);
108 error
= gitfo_prettify_file_path(path_aux
, sizeof(path_aux
), git_index_file
);
109 if (error
< GIT_SUCCESS
)
110 return git__rethrow(error
, "Failed to open repository");
113 /* store GIT_INDEX_FILE */
114 repo
->path_index
= git__strdup(path_aux
);
115 if (repo
->path_index
== NULL
)
122 static int check_repository_dirs(git_repository
*repo
)
124 char path_aux
[GIT_PATH_MAX
];
126 if (gitfo_isdir(repo
->path_repository
) < GIT_SUCCESS
)
127 return git__throw(GIT_ENOTAREPO
, "`%s` is not a folder", repo
->path_repository
);
129 /* Ensure GIT_OBJECT_DIRECTORY exists */
130 if (gitfo_isdir(repo
->path_odb
) < GIT_SUCCESS
)
131 return git__throw(GIT_ENOTAREPO
, "`%s` does not exist", repo
->path_odb
);
133 /* Ensure HEAD file exists */
134 git__joinpath(path_aux
, repo
->path_repository
, GIT_HEAD_FILE
);
135 if (gitfo_exists(path_aux
) < 0)
136 return git__throw(GIT_ENOTAREPO
, "HEAD file is missing");
141 static int guess_repository_dirs(git_repository
*repo
, const char *repository_path
)
143 char buffer
[GIT_PATH_MAX
];
144 const char *path_work_tree
= NULL
;
146 /* Git directory name */
147 if (git__basename_r(buffer
, sizeof(buffer
), repository_path
) < 0)
148 return git__throw(GIT_EINVALIDPATH
, "Unable to parse folder name from `%s`", repository_path
);
150 if (strcmp(buffer
, DOT_GIT
) == 0) {
151 /* Path to working dir */
152 if (git__dirname_r(buffer
, sizeof(buffer
), repository_path
) < 0)
153 return git__throw(GIT_EINVALIDPATH
, "Unable to parse parent folder name from `%s`", repository_path
);
154 path_work_tree
= buffer
;
157 return assign_repository_dirs(repo
, repository_path
, NULL
, NULL
, path_work_tree
);
160 static git_repository
*repository_alloc()
164 git_repository
*repo
= git__malloc(sizeof(git_repository
));
168 memset(repo
, 0x0, sizeof(git_repository
));
170 error
= git_cache_init(&repo
->objects
, GIT_DEFAULT_CACHE_SIZE
, &git_object__free
);
171 if (error
< GIT_SUCCESS
) {
176 if (git_repository__refcache_init(&repo
->references
) < GIT_SUCCESS
) {
184 static int init_odb(git_repository
*repo
)
186 return git_odb_open(&repo
->db
, repo
->path_odb
); /* TODO: Move odb.c to new error handling */
189 int git_repository_open3(git_repository
**repo_out
,
191 git_odb
*object_database
,
192 const char *git_index_file
,
193 const char *git_work_tree
)
195 git_repository
*repo
;
196 int error
= GIT_SUCCESS
;
200 if (object_database
== NULL
)
201 return git__throw(GIT_EINVALIDARGS
, "Failed to open repository. `object_database` can't be null");
203 repo
= repository_alloc();
207 error
= assign_repository_dirs(repo
,
213 if (error
< GIT_SUCCESS
)
216 error
= check_repository_dirs(repo
);
217 if (error
< GIT_SUCCESS
)
220 repo
->db
= object_database
;
226 git_repository_free(repo
);
227 return git__rethrow(error
, "Failed to open repository");
231 int git_repository_open2(git_repository
**repo_out
,
233 const char *git_object_directory
,
234 const char *git_index_file
,
235 const char *git_work_tree
)
237 git_repository
*repo
;
238 int error
= GIT_SUCCESS
;
242 repo
= repository_alloc();
246 error
= assign_repository_dirs(repo
,
248 git_object_directory
,
252 if (error
< GIT_SUCCESS
)
255 error
= check_repository_dirs(repo
);
256 if (error
< GIT_SUCCESS
)
259 error
= init_odb(repo
);
260 if (error
< GIT_SUCCESS
)
267 git_repository_free(repo
);
268 return git__rethrow(error
, "Failed to open repository");
271 int git_repository_open(git_repository
**repo_out
, const char *path
)
273 git_repository
*repo
;
274 int error
= GIT_SUCCESS
;
276 assert(repo_out
&& path
);
278 repo
= repository_alloc();
282 error
= guess_repository_dirs(repo
, path
);
283 if (error
< GIT_SUCCESS
)
286 error
= check_repository_dirs(repo
);
287 if (error
< GIT_SUCCESS
)
290 error
= init_odb(repo
);
291 if (error
< GIT_SUCCESS
)
298 git_repository_free(repo
);
299 return git__rethrow(error
, "Failed to open repository");
302 void git_repository_free(git_repository
*repo
)
307 git_cache_free(&repo
->objects
);
308 git_repository__refcache_free(&repo
->references
);
310 free(repo
->path_workdir
);
311 free(repo
->path_index
);
312 free(repo
->path_repository
);
313 free(repo
->path_odb
);
315 if (repo
->db
!= NULL
)
316 git_odb_close(repo
->db
);
321 git_odb
*git_repository_database(git_repository
*repo
)
327 static int repo_init_reinit(repo_init
*results
)
329 /* TODO: reinit the repository */
330 results
->has_been_reinit
= 1;
331 return git__throw(GIT_ENOTIMPLEMENTED
, "Failed to reinitialize the repository. This feature is not yet implemented");
334 static int repo_init_createhead(git_repository
*repo
)
336 git_reference
*head_reference
;
337 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 */
340 static int repo_init_check_head_existence(char * repository_path
)
342 char temp_path
[GIT_PATH_MAX
];
344 git__joinpath(temp_path
, repository_path
, GIT_HEAD_FILE
);
345 return gitfo_exists(temp_path
);
348 static int repo_init_structure(repo_init
*results
)
350 const int mode
= 0755; /* or 0777 ? */
353 char temp_path
[GIT_PATH_MAX
];
354 char *git_dir
= results
->path_repository
;
356 if (gitfo_mkdir_recurs(git_dir
, mode
))
357 return git__throw(GIT_ERROR
, "Failed to initialize repository structure. Could not mkdir");
359 /* Creates the '/objects/info/' directory */
360 git__joinpath(temp_path
, git_dir
, GIT_OBJECTS_INFO_DIR
);
361 error
= gitfo_mkdir_recurs(temp_path
, mode
);
362 if (error
< GIT_SUCCESS
)
363 return git__rethrow(error
, "Failed to initialize repository structure");
365 /* Creates the '/objects/pack/' directory */
366 git__joinpath(temp_path
, git_dir
, GIT_OBJECTS_PACK_DIR
);
367 error
= gitfo_mkdir(temp_path
, mode
);
368 if (error
< GIT_SUCCESS
)
369 return git__throw(error
, "Unable to create `%s` folder", temp_path
);
371 /* Creates the '/refs/heads/' directory */
372 git__joinpath(temp_path
, git_dir
, GIT_REFS_HEADS_DIR
);
373 error
= gitfo_mkdir_recurs(temp_path
, mode
);
374 if (error
< GIT_SUCCESS
)
375 return git__rethrow(error
, "Failed to initialize repository structure");
377 /* Creates the '/refs/tags/' directory */
378 git__joinpath(temp_path
, git_dir
, GIT_REFS_TAGS_DIR
);
379 error
= gitfo_mkdir(temp_path
, mode
);
380 if (error
< GIT_SUCCESS
)
381 return git__throw(error
, "Unable to create `%s` folder", temp_path
);
383 /* TODO: what's left? templates? */
388 static int repo_init_find_dir(repo_init
*results
, const char* path
)
390 char temp_path
[GIT_PATH_MAX
];
391 int error
= GIT_SUCCESS
;
393 error
= gitfo_prettify_dir_path(temp_path
, sizeof(temp_path
), path
);
394 if (error
< GIT_SUCCESS
)
395 return git__rethrow(error
, "Failed to find directory to initialize repository");
397 if (!results
->is_bare
) {
398 git__joinpath(temp_path
, temp_path
, GIT_DIR
);
401 results
->path_repository
= git__strdup(temp_path
);
402 if (results
->path_repository
== NULL
)
408 int git_repository_init(git_repository
**repo_out
, const char *path
, unsigned is_bare
)
410 int error
= GIT_SUCCESS
;
411 git_repository
*repo
= NULL
;
414 assert(repo_out
&& path
);
416 results
.path_repository
= NULL
;
417 results
.is_bare
= is_bare
;
419 error
= repo_init_find_dir(&results
, path
);
420 if (error
< GIT_SUCCESS
)
423 if (!repo_init_check_head_existence(results
.path_repository
))
424 return repo_init_reinit(&results
);
426 error
= repo_init_structure(&results
);
427 if (error
< GIT_SUCCESS
)
430 repo
= repository_alloc();
436 error
= guess_repository_dirs(repo
, results
.path_repository
);
437 if (error
< GIT_SUCCESS
)
440 assert(repo
->is_bare
== is_bare
);
442 error
= init_odb(repo
);
443 if (error
< GIT_SUCCESS
)
446 error
= repo_init_createhead(repo
);
447 if (error
< GIT_SUCCESS
)
450 /* should never fail */
451 assert(check_repository_dirs(repo
) == GIT_SUCCESS
);
453 free(results
.path_repository
);
458 free(results
.path_repository
);
459 git_repository_free(repo
);
460 return git__rethrow(error
, "Failed to (re)init the repository `%s`", path
);
463 int git_repository_is_empty(git_repository
*repo
)
465 git_reference
*head
, *branch
;
468 error
= git_reference_lookup(&head
, repo
, "HEAD");
469 if (error
< GIT_SUCCESS
)
470 return git__throw(error
, "Failed to determine the emptiness of the repository. An error occured while retrieving the HEAD reference");
472 if (git_reference_type(head
) != GIT_REF_SYMBOLIC
)
473 return git__throw(GIT_EOBJCORRUPTED
, "Failed to determine the emptiness of the repository. HEAD is probably in detached state");
475 return git_reference_resolve(&branch
, head
) == GIT_SUCCESS
? 0 : 1;
478 const char *git_repository_path(git_repository
*repo
)
481 return repo
->path_repository
;
484 const char *git_repository_workdir(git_repository
*repo
)
487 return repo
->path_workdir
;