]> git.proxmox.com Git - libgit2.git/blob - src/repository.c
I broke your bindings
[libgit2.git] / src / repository.c
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 */
25 #include <stdarg.h>
26
27 #include "git2/object.h"
28
29 #include "common.h"
30 #include "repository.h"
31 #include "commit.h"
32 #include "tag.h"
33 #include "blob.h"
34 #include "fileops.h"
35
36 #include "refs.h"
37
38 #define GIT_OBJECTS_INFO_DIR GIT_OBJECTS_DIR "info/"
39 #define GIT_OBJECTS_PACK_DIR GIT_OBJECTS_DIR "pack/"
40
41 #define GIT_BRANCH_MASTER "master"
42
43 typedef struct {
44 char *path_repository;
45 unsigned is_bare:1, has_been_reinit:1;
46 } repo_init;
47
48 /*
49 * Git repository open methods
50 *
51 * Open a repository object from its path
52 */
53 static int assign_repository_dirs(
54 git_repository *repo,
55 const char *git_dir,
56 const char *git_object_directory,
57 const char *git_index_file,
58 const char *git_work_tree)
59 {
60 char path_aux[GIT_PATH_MAX];
61 size_t git_dir_path_len;
62 int error = GIT_SUCCESS;
63
64 assert(repo);
65
66 if (git_dir == NULL)
67 return GIT_ENOTFOUND;
68
69 error = gitfo_prettify_dir_path(path_aux, git_dir);
70 if (error < GIT_SUCCESS)
71 return error;
72
73 git_dir_path_len = strlen(path_aux);
74
75 /* store GIT_DIR */
76 repo->path_repository = git__strdup(path_aux);
77 if (repo->path_repository == NULL)
78 return GIT_ENOMEM;
79
80 /* path to GIT_OBJECT_DIRECTORY */
81 if (git_object_directory == NULL)
82 git__joinpath(path_aux, repo->path_repository, GIT_OBJECTS_DIR);
83 else {
84 error = gitfo_prettify_dir_path(path_aux, git_object_directory);
85 if (error < GIT_SUCCESS)
86 return error;
87 }
88
89 /* Store GIT_OBJECT_DIRECTORY */
90 repo->path_odb = git__strdup(path_aux);
91 if (repo->path_odb == NULL)
92 return GIT_ENOMEM;
93
94 /* path to GIT_WORK_TREE */
95 if (git_work_tree == NULL)
96 repo->is_bare = 1;
97 else {
98 error = gitfo_prettify_dir_path(path_aux, git_work_tree);
99 if (error < GIT_SUCCESS)
100 return error;
101
102 /* Store GIT_WORK_TREE */
103 repo->path_workdir = git__strdup(path_aux);
104 if (repo->path_workdir == NULL)
105 return GIT_ENOMEM;
106
107 /* Path to GIT_INDEX_FILE */
108 if (git_index_file == NULL)
109 git__joinpath(path_aux, repo->path_repository, GIT_INDEX_FILE);
110 else {
111 error = gitfo_prettify_file_path(path_aux, git_index_file);
112 if (error < GIT_SUCCESS)
113 return error;
114 }
115
116 /* store GIT_INDEX_FILE */
117 repo->path_index = git__strdup(path_aux);
118 if (repo->path_index == NULL)
119 return GIT_ENOMEM;
120 }
121
122 return GIT_SUCCESS;
123 }
124
125 static int check_repository_dirs(git_repository *repo)
126 {
127 char path_aux[GIT_PATH_MAX];
128
129 if (gitfo_isdir(repo->path_repository) < GIT_SUCCESS)
130 return GIT_ENOTAREPO;
131
132 /* Ensure GIT_OBJECT_DIRECTORY exists */
133 if (gitfo_isdir(repo->path_odb) < GIT_SUCCESS)
134 return GIT_ENOTAREPO;
135
136 /* Ensure HEAD file exists */
137 git__joinpath(path_aux, repo->path_repository, GIT_HEAD_FILE);
138 if (gitfo_exists(path_aux) < 0)
139 return GIT_ENOTAREPO;
140
141 return GIT_SUCCESS;
142 }
143
144 static int guess_repository_dirs(git_repository *repo, const char *repository_path)
145 {
146 char buffer[GIT_PATH_MAX];
147 const char *path_work_tree = NULL;
148
149 /* Git directory name */
150 if (git__basename_r(buffer, sizeof(buffer), repository_path) < 0)
151 return GIT_EINVALIDPATH;
152
153 if (strcmp(buffer, DOT_GIT) == 0) {
154 /* Path to working dir */
155 if (git__dirname_r(buffer, sizeof(buffer), repository_path) < 0)
156 return GIT_EINVALIDPATH;
157 path_work_tree = buffer;
158 }
159
160 return assign_repository_dirs(repo, repository_path, NULL, NULL, path_work_tree);
161 }
162
163 static git_repository *repository_alloc()
164 {
165 git_repository *repo = git__malloc(sizeof(git_repository));
166 if (!repo)
167 return NULL;
168
169 memset(repo, 0x0, sizeof(git_repository));
170
171 git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
172
173 if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {
174 free(repo);
175 return NULL;
176 }
177
178 return repo;
179 }
180
181 static int init_odb(git_repository *repo)
182 {
183 return git_odb_open(&repo->db, repo->path_odb);
184 }
185
186 int git_repository_open3(git_repository **repo_out,
187 const char *git_dir,
188 git_odb *object_database,
189 const char *git_index_file,
190 const char *git_work_tree)
191 {
192 git_repository *repo;
193 int error = GIT_SUCCESS;
194
195 assert(repo_out);
196
197 if (object_database == NULL)
198 return GIT_ERROR;
199
200 repo = repository_alloc();
201 if (repo == NULL)
202 return GIT_ENOMEM;
203
204 error = assign_repository_dirs(repo,
205 git_dir,
206 NULL,
207 git_index_file,
208 git_work_tree);
209
210 if (error < GIT_SUCCESS)
211 goto cleanup;
212
213 error = check_repository_dirs(repo);
214 if (error < GIT_SUCCESS)
215 goto cleanup;
216
217 repo->db = object_database;
218
219 *repo_out = repo;
220 return GIT_SUCCESS;
221
222 cleanup:
223 git_repository_free(repo);
224 return error;
225 }
226
227
228 int git_repository_open2(git_repository **repo_out,
229 const char *git_dir,
230 const char *git_object_directory,
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 repo = repository_alloc();
240 if (repo == NULL)
241 return GIT_ENOMEM;
242
243 error = assign_repository_dirs(repo,
244 git_dir,
245 git_object_directory,
246 git_index_file,
247 git_work_tree);
248
249 if (error < GIT_SUCCESS)
250 goto cleanup;
251
252 error = check_repository_dirs(repo);
253 if (error < GIT_SUCCESS)
254 goto cleanup;
255
256 error = init_odb(repo);
257 if (error < GIT_SUCCESS)
258 goto cleanup;
259
260 *repo_out = repo;
261 return GIT_SUCCESS;
262
263 cleanup:
264 git_repository_free(repo);
265 return error;
266 }
267
268 int git_repository_open(git_repository **repo_out, const char *path)
269 {
270 git_repository *repo;
271 int error = GIT_SUCCESS;
272
273 assert(repo_out && path);
274
275 repo = repository_alloc();
276 if (repo == NULL)
277 return GIT_ENOMEM;
278
279 error = guess_repository_dirs(repo, path);
280 if (error < GIT_SUCCESS)
281 goto cleanup;
282
283 error = check_repository_dirs(repo);
284 if (error < GIT_SUCCESS)
285 goto cleanup;
286
287 error = init_odb(repo);
288 if (error < GIT_SUCCESS)
289 goto cleanup;
290
291 *repo_out = repo;
292 return GIT_SUCCESS;
293
294 cleanup:
295 git_repository_free(repo);
296 return error;
297 }
298
299 void git_repository_free(git_repository *repo)
300 {
301 if (repo == NULL)
302 return;
303
304 git_cache_free(&repo->objects);
305 git_repository__refcache_free(&repo->references);
306
307 free(repo->path_workdir);
308 free(repo->path_index);
309 free(repo->path_repository);
310 free(repo->path_odb);
311
312 if (repo->db != NULL)
313 git_odb_close(repo->db);
314
315 if (repo->index != NULL)
316 git_index_free(repo->index);
317
318 free(repo);
319 }
320
321 int git_repository_index(git_index **index_out, git_repository *repo)
322 {
323 int error;
324
325 assert(index_out && repo);
326
327 if (repo->index == NULL) {
328 error = git_index_open_inrepo(&repo->index, repo);
329 if (error < GIT_SUCCESS)
330 return error;
331
332 assert(repo->index != NULL);
333 }
334
335 *index_out = repo->index;
336 return GIT_SUCCESS;
337 }
338
339 git_odb *git_repository_database(git_repository *repo)
340 {
341 assert(repo);
342 return repo->db;
343 }
344
345 static int repo_init_reinit(repo_init *results)
346 {
347 /* TODO: reinit the repository */
348 results->has_been_reinit = 1;
349 return GIT_SUCCESS;
350 }
351
352 static int repo_init_createhead(git_repository *repo)
353 {
354 git_reference *head_reference;
355 return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE);
356 }
357
358 static int repo_init_check_head_existence(char * repository_path)
359 {
360 char temp_path[GIT_PATH_MAX];
361
362 git__joinpath(temp_path, repository_path, GIT_HEAD_FILE);
363 return gitfo_exists(temp_path);
364 }
365
366 static int repo_init_structure(repo_init *results)
367 {
368 const int mode = 0755; /* or 0777 ? */
369
370 char temp_path[GIT_PATH_MAX];
371 char *git_dir = results->path_repository;
372
373 if (gitfo_mkdir_recurs(git_dir, mode))
374 return GIT_ERROR;
375
376 /* Creates the '/objects/info/' directory */
377 git__joinpath(temp_path, git_dir, GIT_OBJECTS_INFO_DIR);
378 if (gitfo_mkdir_recurs(temp_path, mode) < GIT_SUCCESS)
379 return GIT_ERROR;
380
381 /* Creates the '/objects/pack/' directory */
382 git__joinpath(temp_path, git_dir, GIT_OBJECTS_PACK_DIR);
383 if (gitfo_mkdir(temp_path, mode))
384 return GIT_ERROR;
385
386 /* Creates the '/refs/heads/' directory */
387 git__joinpath(temp_path, git_dir, GIT_REFS_HEADS_DIR);
388 if (gitfo_mkdir_recurs(temp_path, mode))
389 return GIT_ERROR;
390
391 /* Creates the '/refs/tags/' directory */
392 git__joinpath(temp_path, git_dir, GIT_REFS_TAGS_DIR);
393 if (gitfo_mkdir(temp_path, mode))
394 return GIT_ERROR;
395
396 /* TODO: what's left? templates? */
397
398 return GIT_SUCCESS;
399 }
400
401 static int repo_init_find_dir(repo_init *results, const char* path)
402 {
403 char temp_path[GIT_PATH_MAX];
404 int error = GIT_SUCCESS;
405
406 error = gitfo_prettify_dir_path(temp_path, path);
407 if (error < GIT_SUCCESS)
408 return error;
409
410 if (!results->is_bare) {
411 git__joinpath(temp_path, temp_path, GIT_DIR);
412 }
413
414 results->path_repository = git__strdup(temp_path);
415 if (results->path_repository == NULL)
416 return GIT_ENOMEM;
417
418 return GIT_SUCCESS;
419 }
420
421 int git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare)
422 {
423 int error = GIT_SUCCESS;
424 git_repository *repo = NULL;
425 repo_init results;
426
427 assert(repo_out && path);
428
429 results.path_repository = NULL;
430 results.is_bare = is_bare;
431
432 error = repo_init_find_dir(&results, path);
433 if (error < GIT_SUCCESS)
434 goto cleanup;
435
436 if (!repo_init_check_head_existence(results.path_repository))
437 return repo_init_reinit(&results);
438
439 error = repo_init_structure(&results);
440 if (error < GIT_SUCCESS)
441 goto cleanup;
442
443 repo = repository_alloc();
444 if (repo == NULL) {
445 error = GIT_ENOMEM;
446 goto cleanup;
447 }
448
449 error = guess_repository_dirs(repo, results.path_repository);
450 if (error < GIT_SUCCESS)
451 goto cleanup;
452
453 assert(repo->is_bare == is_bare);
454
455 error = init_odb(repo);
456 if (error < GIT_SUCCESS)
457 goto cleanup;
458
459 error = repo_init_createhead(repo);
460 if (error < GIT_SUCCESS)
461 goto cleanup;
462
463 /* should never fail */
464 assert(check_repository_dirs(repo) == GIT_SUCCESS);
465
466 free(results.path_repository);
467 *repo_out = repo;
468 return GIT_SUCCESS;
469
470 cleanup:
471 free(results.path_repository);
472 git_repository_free(repo);
473 return error;
474 }
475