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