Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
4 - * This file is part of libgit2, distributed under the GNU GPL v2 with
5 - * a Linking Exception. For full terms see the included COPYING file.
6 - */
7 -
8 - #include "refs.h"
9 - #include "hash.h"
10 - #include "repository.h"
11 - #include "futils.h"
12 - #include "filebuf.h"
13 - #include "pack.h"
14 - #include "parse.h"
15 - #include "reflog.h"
16 - #include "refdb.h"
17 - #include "iterator.h"
18 - #include "sortedcache.h"
19 - #include "signature.h"
20 - #include "wildmatch.h"
21 -
22 - #include <git2/tag.h>
23 - #include <git2/object.h>
24 - #include <git2/refdb.h>
25 - #include <git2/branch.h>
26 - #include <git2/sys/refdb_backend.h>
27 - #include <git2/sys/refs.h>
28 - #include <git2/sys/reflog.h>
29 -
30 - #define DEFAULT_NESTING_LEVEL 5
31 - #define MAX_NESTING_LEVEL 10
32 -
33 - enum {
34 - PACKREF_HAS_PEEL = 1,
35 - PACKREF_WAS_LOOSE = 2,
36 - PACKREF_CANNOT_PEEL = 4,
37 - PACKREF_SHADOWED = 8,
38 - };
39 -
40 - enum {
41 - PEELING_NONE = 0,
42 - PEELING_STANDARD,
43 - PEELING_FULL
44 - };
45 -
46 - struct packref {
47 - git_oid oid;
48 - git_oid peel;
49 - char flags;
50 - char name[GIT_FLEX_ARRAY];
51 - };
52 -
53 - typedef struct refdb_fs_backend {
54 - git_refdb_backend parent;
55 -
56 - git_repository *repo;
57 - /* path to git directory */
58 - char *gitpath;
59 - /* path to common objects' directory */
60 - char *commonpath;
61 -
62 - git_sortedcache *refcache;
63 - int peeling_mode;
64 - git_iterator_flag_t iterator_flags;
65 - uint32_t direach_flags;
66 - int fsync;
67 - } refdb_fs_backend;
68 -
69 - static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name);
70 -
71 36081 2 static int packref_cmp(const void *a_, const void *b_)
72 - {
73 36081 2 const struct packref *a = a_, *b = b_;
74 36081 2 return strcmp(a->name, b->name);
75 - }
76 -
77 - 2 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files)static int packed_reload(refdb_fs_backend *backend)
78 - {
79 - int error;
80 - 2 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_buf packedrefs = GIT_BUF_INIT;
81 - char *scan, *eof, *eol;
82 -
83 - 2 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (!backend->gitpath)
84 - 3 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) return 0;
85 -
86 - 4 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) error = git_sortedcache_lockandload(backend->refcache, &packedrefs);
87 -
88 - /*
89 - * If we can't find the packed-refs, clear table and return.
90 - * Any other error just gets passed through.
91 - * If no error, and file wasn't changed, just return.
92 - * Anything else means we need to refresh the packed refs.
93 - */
94 - 5 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (error <= 0) {
95 - 6 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (error == GIT_ENOTFOUND) {
96 - 7 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_sortedcache_clear(backend->refcache, true);
97 - 8 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_error_clear();
98 - 9 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) error = 0;
99 - }
100 - 10 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) return error;
101 - }
102 -
103 - /* At this point, refresh the packed refs from the loaded buffer. */
104 -
105 - 11 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_sortedcache_clear(backend->refcache, false);
106 -
107 - 12 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) scan = (char *)packedrefs.ptr;
108 - 12 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) eof = scan + packedrefs.size;
109 -
110 - 12 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) backend->peeling_mode = PEELING_NONE;
111 -
112 - 12 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (*scan == '#') {
113 - static const char *traits_header = "# pack-refs with: ";
114 -
115 - 13,14 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (git__prefixcmp(scan, traits_header) == 0) {
116 - 15 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) scan += strlen(traits_header);
117 - 15 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) eol = strchr(scan, '\n');
118 -
119 - 15 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (!eol)
120 - 16 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) goto parse_failed;
121 - 17 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) *eol = '\0';
122 -
123 - 17 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (strstr(scan, " fully-peeled ") != NULL) {
124 - 18 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) backend->peeling_mode = PEELING_FULL;
125 - 19 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) } else if (strstr(scan, " peeled ") != NULL) {
126 - 20 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) backend->peeling_mode = PEELING_STANDARD;
127 - }
128 -
129 - 21 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) scan = eol + 1;
130 - }
131 - }
132 -
133 - 22,26,27 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) while (scan < eof && *scan == '#') {
134 - 23 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (!(eol = strchr(scan, '\n')))
135 - 24 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) goto parse_failed;
136 - 25 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) scan = eol + 1;
137 - }
138 -
139 - 28,59 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) while (scan < eof) {
140 - struct packref *ref;
141 - git_oid oid;
142 -
143 - /* parse "<OID> <refname>\n" */
144 -
145 - 29,30 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (git_oid_fromstr(&oid, scan) < 0)
146 - 31,58 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) goto parse_failed;
147 - 32 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) scan += GIT_OID_HEXSZ;
148 -
149 - 32 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (*scan++ != ' ')
150 - 33 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) goto parse_failed;
151 - 34 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (!(eol = strchr(scan, '\n')))
152 - 35 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) goto parse_failed;
153 - 36 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) *eol = '\0';
154 - 36 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (eol[-1] == '\r')
155 - 37 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) eol[-1] = '\0';
156 -
157 - 38,39 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (git_sortedcache_upsert((void **)&ref, backend->refcache, scan) < 0)
158 - 40 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) goto parse_failed;
159 - 41 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) scan = eol + 1;
160 -
161 - 41 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_oid_cpy(&ref->oid, &oid);
162 -
163 - /* look for optional "^<OID>\n" */
164 -
165 - 42 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (*scan == '^') {
166 - 43,44 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (git_oid_fromstr(&oid, scan + 1) < 0)
167 - 45 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) goto parse_failed;
168 - 46 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) scan += GIT_OID_HEXSZ + 1;
169 -
170 - 46 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (scan < eof) {
171 - 47 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) if (!(eol = strchr(scan, '\n')))
172 - 48 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) goto parse_failed;
173 - 49 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) scan = eol + 1;
174 - }
175 -
176 - 50 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_oid_cpy(&ref->peel, &oid);
177 - 51 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) ref->flags |= PACKREF_HAS_PEEL;
178 - }
179 - 52,53 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) else if (backend->peeling_mode == PEELING_FULL ||
180 - 53,55 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) (backend->peeling_mode == PEELING_STANDARD &&
181 - 54 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) == 0))
182 - 56,57 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) ref->flags |= PACKREF_CANNOT_PEEL;
183 - }
184 -
185 - 60 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_sortedcache_wunlock(backend->refcache);
186 - 61 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_buf_dispose(&packedrefs);
187 -
188 - 62 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) return 0;
189 -
190 - parse_failed:
191 - 63 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_error_set(GIT_ERROR_REFERENCE, "corrupted packed references file");
192 -
193 - 64 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_sortedcache_clear(backend->refcache, false);
194 - 65 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_sortedcache_wunlock(backend->refcache);
195 - 66 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) git_buf_dispose(&packedrefs);
196 -
197 - 67 suppressed: function cannot be solved packed_reload (automatic due to inconsistent arc counts in .gcda files) return -1;
198 - }
199 -
200 18500 2 static int loose_parse_oid(
201 - git_oid *oid, const char *filename, git_buf *file_content)
202 - {
203 18500 2 const char *str = git_buf_cstr(file_content);
204 -
205 18499 3,4 if (git_buf_len(file_content) < GIT_OID_HEXSZ)
206 4 5 goto corrupted;
207 -
208 - /* we need to get 40 OID characters from the file */
209 18492 6,7 if (git_oid_fromstr(oid, str) < 0)
210 ##### 8 goto corrupted;
211 -
212 - /* If the file is longer than 40 chars, the 41st must be a space */
213 18485 9 str += GIT_OID_HEXSZ;
214 18485 9-11 if (*str == '\0' || git__isspace(*str))
215 18487 12 return 0;
216 -
217 - corrupted:
218 4 13 git_error_set(GIT_ERROR_REFERENCE, "corrupted loose reference file: %s", filename);
219 4 14 return -1;
220 - }
221 -
222 40732 2 static int loose_readbuffer(git_buf *buf, const char *base, const char *path)
223 - {
224 - int error;
225 -
226 - /* build full path to file */
227 40736 2-5 if ((error = git_buf_joinpath(buf, base, path)) < 0 ||
228 40736 4 (error = git_futils_readbuffer(buf, buf->ptr)) < 0)
229 13921 6 git_buf_dispose(buf);
230 -
231 40733 7 return error;
232 - }
233 -
234 754 2 static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name)
235 - {
236 754 2 int error = 0;
237 754 2 git_buf ref_file = GIT_BUF_INIT;
238 754 2 struct packref *ref = NULL;
239 - git_oid oid;
240 -
241 - /* if we fail to load the loose reference, assume someone changed
242 - * the filesystem under us and skip it...
243 - */
244 754 2,3 if (loose_readbuffer(&ref_file, backend->gitpath, name) < 0) {
245 26 4 git_error_clear();
246 26 5 goto done;
247 - }
248 -
249 - /* skip symbolic refs */
250 727 6-8 if (!git__prefixcmp(git_buf_cstr(&ref_file), GIT_SYMREF))
251 144 9 goto done;
252 -
253 - /* parse OID from file */
254 581 10,11 if ((error = loose_parse_oid(&oid, name, &ref_file)) < 0)
255 ##### 12 goto done;
256 -
257 581 13 git_sortedcache_wlock(backend->refcache);
258 -
259 584 14,15 if (!(error = git_sortedcache_upsert(
260 - (void **)&ref, backend->refcache, name))) {
261 -
262 584 16 git_oid_cpy(&ref->oid, &oid);
263 583 17 ref->flags = PACKREF_WAS_LOOSE;
264 - }
265 -
266 583 18 git_sortedcache_wunlock(backend->refcache);
267 -
268 - done:
269 754 19 git_buf_dispose(&ref_file);
270 754 20 return error;
271 - }
272 -
273 971 2 static int _dirent_loose_load(void *payload, git_buf *full_path)
274 - {
275 971 2 refdb_fs_backend *backend = payload;
276 - const char *file_path;
277 -
278 971 2,3 if (git__suffixcmp(full_path->ptr, ".lock") == 0)
279 77 4 return 0;
280 -
281 896 5,6 if (git_path_isdir(full_path->ptr)) {
282 142 7 int error = git_path_direach(
283 - full_path, backend->direach_flags, _dirent_loose_load, backend);
284 - /* Race with the filesystem, ignore it */
285 142 8 if (error == GIT_ENOTFOUND) {
286 ##### 9 git_error_clear();
287 ##### 10 return 0;
288 - }
289 -
290 142 11 return error;
291 - }
292 -
293 754 12 file_path = full_path->ptr + strlen(backend->gitpath);
294 -
295 754 12 return loose_lookup_to_packfile(backend, file_path);
296 - }
297 -
298 - /*
299 - * Load all the loose references from the repository
300 - * into the in-memory Packfile, and build a vector with
301 - * all the references so it can be written back to
302 - * disk.
303 - */
304 44 2 static int packed_loadloose(refdb_fs_backend *backend)
305 - {
306 - int error;
307 44 2 git_buf refs_path = GIT_BUF_INIT;
308 -
309 44 2,3 if (git_buf_joinpath(&refs_path, backend->gitpath, GIT_REFS_DIR) < 0)
310 ##### 4 return -1;
311 -
312 - /*
313 - * Load all the loose files from disk into the Packfile table.
314 - * This will overwrite any old packed entries with their
315 - * updated loose versions
316 - */
317 44 5 error = git_path_direach(
318 - &refs_path, backend->direach_flags, _dirent_loose_load, backend);
319 -
320 44 6 git_buf_dispose(&refs_path);
321 -
322 44 7 return error;
323 - }
324 -
325 802 2 static int refdb_fs_backend__exists(
326 - int *exists,
327 - git_refdb_backend *_backend,
328 - const char *ref_name)
329 - {
330 802 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
331 802 2 git_buf ref_path = GIT_BUF_INIT;
332 - int error;
333 -
334 802 2,3 assert(backend);
335 -
336 802 4 *exists = 0;
337 -
338 802 4,5 if ((error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0)
339 ##### 6 goto out;
340 -
341 802 7,8 if (git_path_isfile(ref_path.ptr)) {
342 14 9 *exists = 1;
343 14 9 goto out;
344 - }
345 -
346 788 10,11 if ((error = packed_reload(backend)) < 0)
347 ##### 12 goto out;
348 -
349 788 13,14 if (git_sortedcache_lookup(backend->refcache, ref_name) != NULL) {
350 ##### 15 *exists = 1;
351 ##### 15 goto out;
352 - }
353 -
354 - out:
355 802 16 git_buf_dispose(&ref_path);
356 802 17 return error;
357 - }
358 -
359 8477 2 static const char *loose_parse_symbolic(git_buf *file_content)
360 - {
361 8477 2 const unsigned int header_len = (unsigned int)strlen(GIT_SYMREF);
362 - const char *refname_start;
363 -
364 8477 2 refname_start = (const char *)file_content->ptr;
365 -
366 8477 2,3 if (git_buf_len(file_content) < header_len + 1) {
367 ##### 4 git_error_set(GIT_ERROR_REFERENCE, "corrupted loose reference file");
368 ##### 5 return NULL;
369 - }
370 -
371 - /*
372 - * Assume we have already checked for the header
373 - * before calling this function
374 - */
375 8477 6 refname_start += header_len;
376 -
377 8477 6 return refname_start;
378 - }
379 -
380 - /*
381 - * Returns whether a reference is stored per worktree or not.
382 - * Per-worktree references are:
383 - *
384 - * - all pseudorefs, e.g. HEAD and MERGE_HEAD
385 - * - all references stored inside of "refs/bisect/"
386 - */
387 - 2 suppressed: function cannot be solved is_per_worktree_ref (automatic due to inconsistent arc counts in .gcda files)static bool is_per_worktree_ref(const char *ref_name)
388 - {
389 - 2,3,5 suppressed: function cannot be solved is_per_worktree_ref (automatic due to inconsistent arc counts in .gcda files) return git__prefixcmp(ref_name, "refs/") != 0 ||
390 - 4 suppressed: function cannot be solved is_per_worktree_ref (automatic due to inconsistent arc counts in .gcda files) git__prefixcmp(ref_name, "refs/bisect/") == 0;
391 - }
392 -
393 39983 2 static int loose_lookup(
394 - git_reference **out,
395 - refdb_fs_backend *backend,
396 - const char *ref_name)
397 - {
398 39983 2 git_buf ref_file = GIT_BUF_INIT;
399 39983 2 int error = 0;
400 - const char *ref_dir;
401 -
402 39983 2 if (out)
403 36099 3 *out = NULL;
404 -
405 39986 4,5 if (is_per_worktree_ref(ref_name))
406 9165 6 ref_dir = backend->gitpath;
407 - else
408 30821 7 ref_dir = backend->commonpath;
409 -
410 39986 8,9 if ((error = loose_readbuffer(&ref_file, ref_dir, ref_name)) < 0)
411 - /* cannot read loose ref file - gah */;
412 26087 10-12 else if (git__prefixcmp(git_buf_cstr(&ref_file), GIT_SYMREF) == 0) {
413 - const char *target;
414 -
415 8477 13 git_buf_rtrim(&ref_file);
416 -
417 8477 14,15 if (!(target = loose_parse_symbolic(&ref_file)))
418 ##### 16 error = -1;
419 8477 17 else if (out != NULL)
420 8477 18-20 *out = git_reference__alloc_symbolic(ref_name, target);
421 - } else {
422 - git_oid oid;
423 -
424 17610 21-23 if (!(error = loose_parse_oid(&oid, ref_name, &ref_file)) &&
425 - out != NULL)
426 17608 24-26 *out = git_reference__alloc(ref_name, &oid, NULL);
427 - }
428 -
429 39981 27 git_buf_dispose(&ref_file);
430 39987 28 return error;
431 - }
432 -
433 13634 2 static int ref_error_notfound(const char *name)
434 - {
435 13634 2 git_error_set(GIT_ERROR_REFERENCE, "reference '%s' not found", name);
436 13634 3 return GIT_ENOTFOUND;
437 - }
438 -
439 13892 2 static int packed_lookup(
440 - git_reference **out,
441 - refdb_fs_backend *backend,
442 - const char *ref_name)
443 - {
444 13892 2 int error = 0;
445 - struct packref *entry;
446 -
447 13893 2,3 if ((error = packed_reload(backend)) < 0)
448 ##### 4 return error;
449 -
450 13893 5,6 if (git_sortedcache_rlock(backend->refcache) < 0)
451 ##### 7 return -1;
452 -
453 13893 8 entry = git_sortedcache_lookup(backend->refcache, ref_name);
454 13893 9 if (!entry) {
455 13634 10 error = ref_error_notfound(ref_name);
456 - } else {
457 259 11 *out = git_reference__alloc(ref_name, &entry->oid, &entry->peel);
458 259 12 if (!*out)
459 ##### 13 error = -1;
460 - }
461 -
462 13893 14 git_sortedcache_runlock(backend->refcache);
463 -
464 13893 15 return error;
465 - }
466 -
467 35267 2 static int refdb_fs_backend__lookup(
468 - git_reference **out,
469 - git_refdb_backend *_backend,
470 - const char *ref_name)
471 - {
472 35267 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
473 - int error;
474 -
475 35267 2,3 assert(backend);
476 -
477 35267 4,5 if (!(error = loose_lookup(out, backend, ref_name)))
478 21375 6 return 0;
479 -
480 - /* only try to lookup this reference on the packfile if it
481 - * wasn't found on the loose refs; not if there was a critical error */
482 13892 7 if (error == GIT_ENOTFOUND) {
483 13892 8 git_error_clear();
484 13892 9 error = packed_lookup(out, backend, ref_name);
485 - }
486 -
487 13893 10 return error;
488 - }
489 -
490 - typedef struct {
491 - git_reference_iterator parent;
492 -
493 - char *glob;
494 -
495 - git_pool pool;
496 - git_vector loose;
497 -
498 - git_sortedcache *cache;
499 - size_t loose_pos;
500 - size_t packed_pos;
501 - } refdb_fs_iter;
502 -
503 488 2 static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter)
504 - {
505 488 2 refdb_fs_iter *iter = GIT_CONTAINER_OF(_iter, refdb_fs_iter, parent);
506 -
507 488 2 git_vector_free(&iter->loose);
508 488 3 git_pool_clear(&iter->pool);
509 488 4 git_sortedcache_free(iter->cache);
510 488 5 git__free(iter);
511 488 6 }
512 -
513 488 2 static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter)
514 - {
515 488 2 int error = 0;
516 488 2 git_buf path = GIT_BUF_INIT;
517 488 2 git_iterator *fsit = NULL;
518 488 2 git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT;
519 488 2 const git_index_entry *entry = NULL;
520 488 2 const char *ref_prefix = GIT_REFS_DIR;
521 488 2 size_t ref_prefix_len = strlen(ref_prefix);
522 -
523 488 2 if (!backend->commonpath) /* do nothing if no commonpath for loose refs */
524 1 3 return 0;
525 -
526 487 4 fsit_opts.flags = backend->iterator_flags;
527 -
528 487 4 if (iter->glob) {
529 61 5 const char *last_sep = NULL;
530 - const char *pos;
531 539 5,9,11 for (pos = iter->glob; *pos; ++pos) {
532 539 6 switch (*pos) {
533 - case '?':
534 - case '*':
535 - case '[':
536 - case '\\':
537 61 7 break;
538 - case '/':
539 86 8 last_sep = pos;
540 - /* FALLTHROUGH */
541 - default:
542 478 9 continue;
543 - }
544 61 10 break;
545 - }
546 61 12 if (last_sep) {
547 58 13 ref_prefix = iter->glob;
548 58 13 ref_prefix_len = (last_sep - ref_prefix) + 1;
549 - }
550 - }
551 -
552 487 14-17 if ((error = git_buf_printf(&path, "%s/", backend->commonpath)) < 0 ||
553 - (error = git_buf_put(&path, ref_prefix, ref_prefix_len)) < 0) {
554 ##### 18 git_buf_dispose(&path);
555 ##### 19 return error;
556 - }
557 -
558 487 20,21 if ((error = git_iterator_for_filesystem(&fsit, path.ptr, &fsit_opts)) < 0) {
559 1 22 git_buf_dispose(&path);
560 1 23-27 return (iter->glob && error == GIT_ENOTFOUND)? 0 : error;
561 - }
562 -
563 486 28 error = git_buf_sets(&path, ref_prefix);
564 -
565 5320 29,43-45 while (!error && !git_iterator_advance(&entry, fsit)) {
566 - const char *ref_name;
567 - char *ref_dup;
568 -
569 4834 30 git_buf_truncate(&path, ref_prefix_len);
570 4834 31 git_buf_puts(&path, entry->path);
571 4834 32 ref_name = git_buf_cstr(&path);
572 -
573 4835 33-35 if (git__suffixcmp(ref_name, ".lock") == 0 ||
574 4821 35-37 (iter->glob && wildmatch(iter->glob, ref_name, 0) != 0))
575 32 38 continue;
576 -
577 4803 39 ref_dup = git_pool_strdup(&iter->pool, ref_name);
578 4802 40 if (!ref_dup)
579 ##### 41 error = -1;
580 - else
581 4802 42 error = git_vector_insert(&iter->loose, ref_dup);
582 - }
583 -
584 485 46 git_iterator_free(fsit);
585 486 47 git_buf_dispose(&path);
586 -
587 486 48 return error;
588 - }
589 -
590 - 2 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files)static int refdb_fs_backend__iterator_next(
591 - git_reference **out, git_reference_iterator *_iter)
592 - {
593 - 2 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) int error = GIT_ITEROVER;
594 - 2 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) refdb_fs_iter *iter = GIT_CONTAINER_OF(_iter, refdb_fs_iter, parent);
595 - 2 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) refdb_fs_backend *backend = GIT_CONTAINER_OF(iter->parent.db->backend, refdb_fs_backend, parent);
596 - struct packref *ref;
597 -
598 - 2,11 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) while (iter->loose_pos < iter->loose.length) {
599 - 3 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) const char *path = git_vector_get(&iter->loose, iter->loose_pos++);
600 -
601 - 4,5 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) if (loose_lookup(out, backend, path) == 0) {
602 - 6 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) ref = git_sortedcache_lookup(iter->cache, path);
603 - 7 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) if (ref)
604 - 8 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) ref->flags |= PACKREF_SHADOWED;
605 -
606 - 9 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) return 0;
607 - }
608 -
609 - 10 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) git_error_clear();
610 - }
611 -
612 - 12 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) error = GIT_ITEROVER;
613 - 12,27,28 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
614 - 13 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
615 - 14 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) if (!ref) /* stop now if another thread deleted refs and we past end */
616 - 15 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) break;
617 -
618 - 16 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) if (ref->flags & PACKREF_SHADOWED)
619 - 17 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) continue;
620 - 18-20 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) if (iter->glob && wildmatch(iter->glob, ref->name, 0) != 0)
621 - 21 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) continue;
622 -
623 - 22 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) *out = git_reference__alloc(ref->name, &ref->oid, &ref->peel);
624 - 23-25 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) error = (*out != NULL) ? 0 : -1;
625 - 26 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) break;
626 - }
627 -
628 - 29 suppressed: function cannot be solved refdb_fs_backend__iterator_next (automatic due to inconsistent arc counts in .gcda files) return error;
629 - }
630 -
631 4400 2 static int refdb_fs_backend__iterator_next_name(
632 - const char **out, git_reference_iterator *_iter)
633 - {
634 4400 2 int error = GIT_ITEROVER;
635 4400 2 refdb_fs_iter *iter = GIT_CONTAINER_OF(_iter, refdb_fs_iter, parent);
636 4400 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(iter->parent.db->backend, refdb_fs_backend, parent);
637 - struct packref *ref;
638 -
639 4401 2,11 while (iter->loose_pos < iter->loose.length) {
640 3882 3 const char *path = git_vector_get(&iter->loose, iter->loose_pos++);
641 - struct packref *ref;
642 -
643 3882 4,5 if (loose_lookup(NULL, backend, path) == 0) {
644 3881 6 ref = git_sortedcache_lookup(iter->cache, path);
645 3881 7 if (ref)
646 156 8 ref->flags |= PACKREF_SHADOWED;
647 -
648 3881 9 *out = path;
649 3881 9 return 0;
650 - }
651 -
652 1 10 git_error_clear();
653 - }
654 -
655 519 12 error = GIT_ITEROVER;
656 679 12,23,24 while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
657 330 13 ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
658 330 14 if (!ref) /* stop now if another thread deleted refs and we past end */
659 ##### 15 break;
660 -
661 330 16 if (ref->flags & PACKREF_SHADOWED)
662 155 17 continue;
663 175 18-20 if (iter->glob && wildmatch(iter->glob, ref->name, 0) != 0)
664 5 21 continue;
665 -
666 170 22 *out = ref->name;
667 170 22 error = 0;
668 170 22 break;
669 - }
670 -
671 519 25 return error;
672 - }
673 -
674 488 2 static int refdb_fs_backend__iterator(
675 - git_reference_iterator **out, git_refdb_backend *_backend, const char *glob)
676 - {
677 488 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
678 488 2 refdb_fs_iter *iter = NULL;
679 - int error;
680 -
681 488 2,3 assert(backend);
682 -
683 488 4 iter = git__calloc(1, sizeof(refdb_fs_iter));
684 488 5,6 GIT_ERROR_CHECK_ALLOC(iter);
685 -
686 488 7,8 if ((error = git_pool_init(&iter->pool, 1)) < 0)
687 ##### 9 goto out;
688 -
689 488 10,11 if ((error = git_vector_init(&iter->loose, 8, NULL)) < 0)
690 ##### 12 goto out;
691 -
692 488 13,15 if (glob != NULL &&
693 61 14 (iter->glob = git_pool_strdup(&iter->pool, glob)) == NULL) {
694 ##### 16 error = GIT_ERROR_NOMEMORY;
695 ##### 16 goto out;
696 - }
697 -
698 488 17,18 if ((error = iter_load_loose_paths(backend, iter)) < 0)
699 ##### 19 goto out;
700 -
701 488 20,21 if ((error = packed_reload(backend)) < 0)
702 ##### 22 goto out;
703 -
704 488 23,24 if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
705 ##### 25 goto out;
706 -
707 488 26 iter->parent.next = refdb_fs_backend__iterator_next;
708 488 26 iter->parent.next_name = refdb_fs_backend__iterator_next_name;
709 488 26 iter->parent.free = refdb_fs_backend__iterator_free;
710 -
711 488 26 *out = (git_reference_iterator *)iter;
712 - out:
713 488 27 if (error)
714 ##### 28 refdb_fs_backend__iterator_free((git_reference_iterator *)iter);
715 488 29 return error;
716 - }
717 -
718 5122 2 static bool ref_is_available(
719 - const char *old_ref, const char *new_ref, const char *this_ref)
720 - {
721 5122 2,3 if (old_ref == NULL || strcmp(old_ref, this_ref)) {
722 5114 4 size_t reflen = strlen(this_ref);
723 5114 4 size_t newlen = strlen(new_ref);
724 5114 4 size_t cmplen = reflen < newlen ? reflen : newlen;
725 5114 4-6 const char *lead = reflen < newlen ? new_ref : this_ref;
726 -
727 5114 7,8 if (!strncmp(new_ref, this_ref, cmplen) && lead[cmplen] == '/') {
728 1 9 return false;
729 - }
730 - }
731 -
732 5121 10 return true;
733 - }
734 -
735 2268 2 static int reference_path_available(
736 - refdb_fs_backend *backend,
737 - const char *new_ref,
738 - const char* old_ref,
739 - int force)
740 - {
741 - size_t i;
742 - int error;
743 -
744 2268 2,3 if ((error = packed_reload(backend)) < 0)
745 ##### 4 return error;
746 -
747 2268 5 if (!force) {
748 - int exists;
749 -
750 802 6,7 if ((error = refdb_fs_backend__exists(
751 - &exists, (git_refdb_backend *)backend, new_ref)) < 0) {
752 14 8,13 return error;
753 - }
754 -
755 802 9 if (exists) {
756 14 10 git_error_set(GIT_ERROR_REFERENCE,
757 - "failed to write reference '%s': a reference with "
758 - "that name already exists.", new_ref);
759 788 11,12 return GIT_EEXISTS;
760 - }
761 - }
762 -
763 2254 14 git_sortedcache_rlock(backend->refcache);
764 -
765 7376 15,23-25 for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) {
766 5121 16 struct packref *ref = git_sortedcache_entry(backend->refcache, i);
767 -
768 5123 17-19 if (ref && !ref_is_available(old_ref, new_ref, ref->name)) {
769 1 20 git_sortedcache_runlock(backend->refcache);
770 1 21 git_error_set(GIT_ERROR_REFERENCE,
771 - "path to reference '%s' collides with existing one", new_ref);
772 1 22 return -1;
773 - }
774 - }
775 -
776 2253 26 git_sortedcache_runlock(backend->refcache);
777 2253 27 return 0;
778 - }
779 -
780 2821 2 static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *name)
781 - {
782 - int error, filebuf_flags;
783 2821 2 git_buf ref_path = GIT_BUF_INIT;
784 - const char *basedir;
785 -
786 2821 2-5 assert(file && backend && name);
787 -
788 2821 6,7 if (!git_path_isvalid(backend->repo, name, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
789 ##### 8 git_error_set(GIT_ERROR_INVALID, "invalid reference name '%s'", name);
790 ##### 9 return GIT_EINVALIDSPEC;
791 - }
792 -
793 2821 10,11 if (is_per_worktree_ref(name))
794 295 12 basedir = backend->gitpath;
795 - else
796 2526 13 basedir = backend->commonpath;
797 -
798 - /* Remove a possibly existing empty directory hierarchy
799 - * which name would collide with the reference name
800 - */
801 2821 14,15 if ((error = git_futils_rmdir_r(name, basedir, GIT_RMDIR_SKIP_NONEMPTY)) < 0)
802 ##### 16 return error;
803 -
804 2821 17,18 if (git_buf_joinpath(&ref_path, basedir, name) < 0)
805 ##### 19 return -1;
806 -
807 2821 20 filebuf_flags = GIT_FILEBUF_CREATE_LEADING_DIRS;
808 2821 20 if (backend->fsync)
809 36 21 filebuf_flags |= GIT_FILEBUF_FSYNC;
810 -
811 2821 22 error = git_filebuf_open(file, ref_path.ptr, filebuf_flags, GIT_REFS_FILE_MODE);
812 -
813 2821 23 if (error == GIT_EDIRECTORY)
814 4 24 git_error_set(GIT_ERROR_REFERENCE, "cannot lock ref '%s', there are refs beneath that folder", name);
815 -
816 2821 25 git_buf_dispose(&ref_path);
817 2821 26 return error;
818 - }
819 -
820 2101 2 static int loose_commit(git_filebuf *file, const git_reference *ref)
821 - {
822 2101 2-4 assert(file && ref);
823 -
824 2101 5 if (ref->type == GIT_REFERENCE_DIRECT) {
825 - char oid[GIT_OID_HEXSZ + 1];
826 1883 6 git_oid_nfmt(oid, sizeof(oid), &ref->target.oid);
827 -
828 1883 7,8 git_filebuf_printf(file, "%s\n", oid);
829 218 9 } else if (ref->type == GIT_REFERENCE_SYMBOLIC) {
830 218 10 git_filebuf_printf(file, GIT_SYMREF "%s\n", ref->target.symbolic);
831 - } else {
832 - 11 assert(0); /* don't let this happen */
833 - }
834 -
835 2101 12 return git_filebuf_commit(file);
836 - }
837 -
838 31 2 static int refdb_fs_backend__lock(void **out, git_refdb_backend *_backend, const char *refname)
839 - {
840 - int error;
841 - git_filebuf *lock;
842 31 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
843 -
844 31 2 lock = git__calloc(1, sizeof(git_filebuf));
845 31 3,4 GIT_ERROR_CHECK_ALLOC(lock);
846 -
847 31 5,6 if ((error = loose_lock(lock, backend, refname)) < 0) {
848 1 7 git__free(lock);
849 1 8 return error;
850 - }
851 -
852 30 9 *out = lock;
853 30 9 return 0;
854 - }
855 -
856 - static int refdb_fs_backend__write_tail(
857 - git_refdb_backend *_backend,
858 - const git_reference *ref,
859 - git_filebuf *file,
860 - int update_reflog,
861 - const git_oid *old_id,
862 - const char *old_target,
863 - const git_signature *who,
864 - const char *message);
865 -
866 - static int refdb_fs_backend__delete_tail(
867 - git_refdb_backend *_backend,
868 - git_filebuf *file,
869 - const char *ref_name,
870 - const git_oid *old_id,
871 - const char *old_target);
872 -
873 30 2 static int refdb_fs_backend__unlock(git_refdb_backend *backend, void *payload, int success, int update_reflog,
874 - const git_reference *ref, const git_signature *sig, const char *message)
875 - {
876 30 2 git_filebuf *lock = (git_filebuf *) payload;
877 30 2 int error = 0;
878 -
879 30 2 if (success == 2)
880 5 3 error = refdb_fs_backend__delete_tail(backend, lock, ref->name, NULL, NULL);
881 25 4 else if (success)
882 10 5 error = refdb_fs_backend__write_tail(backend, ref, lock, update_reflog, NULL, NULL, sig, message);
883 - else
884 15 6 git_filebuf_cleanup(lock);
885 -
886 30 7 git__free(lock);
887 30 8 return error;
888 - }
889 -
890 - /*
891 - * Find out what object this reference resolves to.
892 - *
893 - * For references that point to a 'big' tag (e.g. an
894 - * actual tag object on the repository), we need to
895 - * cache on the packfile the OID of the object to
896 - * which that 'big tag' is pointing to.
897 - */
898 1965 2 static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref)
899 - {
900 - git_object *object;
901 -
902 1965 2,3 if (ref->flags & PACKREF_HAS_PEEL || ref->flags & PACKREF_CANNOT_PEEL)
903 1477 4 return 0;
904 -
905 - /*
906 - * Find the tagged object in the repository
907 - */
908 488 5,6 if (git_object_lookup(&object, backend->repo, &ref->oid, GIT_OBJECT_ANY) < 0)
909 ##### 7 return -1;
910 -
911 - /*
912 - * If the tagged object is a Tag object, we need to resolve it;
913 - * if the ref is actually a 'weak' ref, we don't need to resolve
914 - * anything.
915 - */
916 488 8,9 if (git_object_type(object) == GIT_OBJECT_TAG) {
917 46 10 git_tag *tag = (git_tag *)object;
918 -
919 - /*
920 - * Find the object pointed at by this tag
921 - */
922 46 10,11 git_oid_cpy(&ref->peel, git_tag_target_id(tag));
923 46 12 ref->flags |= PACKREF_HAS_PEEL;
924 -
925 - /*
926 - * The reference has now cached the resolved OID, and is
927 - * marked at such. When written to the packfile, it'll be
928 - * accompanied by this resolved oid
929 - */
930 - }
931 -
932 488 13 git_object_free(object);
933 488 14 return 0;
934 - }
935 -
936 - /*
937 - * Write a single reference into a packfile
938 - */
939 1965 2 static int packed_write_ref(struct packref *ref, git_filebuf *file)
940 - {
941 - char oid[GIT_OID_HEXSZ + 1];
942 1965 2 git_oid_nfmt(oid, sizeof(oid), &ref->oid);
943 -
944 - /*
945 - * For references that peel to an object in the repo, we must
946 - * write the resulting peel on a separate line, e.g.
947 - *
948 - * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4
949 - * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100
950 - *
951 - * This obviously only applies to tags.
952 - * The required peels have already been loaded into `ref->peel_target`.
953 - */
954 1965 3 if (ref->flags & PACKREF_HAS_PEEL) {
955 - char peel[GIT_OID_HEXSZ + 1];
956 77 4 git_oid_nfmt(peel, sizeof(peel), &ref->peel);
957 -
958 77 5,6 if (git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel) < 0)
959 77 7,8 return -1;
960 - } else {
961 1888 9,10 if (git_filebuf_printf(file, "%s %s\n", oid, ref->name) < 0)
962 ##### 11 return -1;
963 - }
964 -
965 1965 12 return 0;
966 - }
967 -
968 - /*
969 - * Remove all loose references
970 - *
971 - * Once we have successfully written a packfile,
972 - * all the loose references that were packed must be
973 - * removed from disk.
974 - *
975 - * This is a dangerous method; make sure the packfile
976 - * is well-written, because we are destructing references
977 - * here otherwise.
978 - */
979 46 2 static int packed_remove_loose(refdb_fs_backend *backend)
980 - {
981 - size_t i;
982 46 2 git_filebuf lock = GIT_FILEBUF_INIT;
983 46 2 git_buf ref_content = GIT_BUF_INIT;
984 46 2 int error = 0;
985 -
986 - /* backend->refcache is already locked when this is called */
987 -
988 1898 2,31-33 for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) {
989 1860 3 struct packref *ref = git_sortedcache_entry(backend->refcache, i);
990 - git_oid current_id;
991 -
992 1860 4,5 if (!ref || !(ref->flags & PACKREF_WAS_LOOSE))
993 1540 6,30 continue;
994 -
995 387 7 git_filebuf_cleanup(&lock);
996 -
997 - /* We need to stop anybody from updating the ref while we try to do a safe delete */
998 387 8 error = loose_lock(&lock, backend, ref->name);
999 - /* If someone else is updating it, let them do it */
1000 387 9,10 if (error == GIT_EEXISTS || error == GIT_ENOTFOUND)
1001 ##### 11 continue;
1002 -
1003 387 12 if (error < 0) {
1004 8 13 git_buf_dispose(&ref_content);
1005 8 14 git_error_set(GIT_ERROR_REFERENCE, "failed to lock loose reference '%s'", ref->name);
1006 8 15 return error;
1007 - }
1008 -
1009 379 16 error = git_futils_readbuffer(&ref_content, lock.path_original);
1010 - /* Someone else beat us to cleaning up the ref, let's simply continue */
1011 379 17 if (error == GIT_ENOTFOUND)
1012 67 18 continue;
1013 -
1014 - /* This became a symref between us packing and trying to delete it, so ignore it */
1015 312 19,20 if (!git__prefixcmp(ref_content.ptr, GIT_SYMREF))
1016 ##### 21 continue;
1017 -
1018 - /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */
1019 312 22,23 if (loose_parse_oid(&current_id, lock.path_original, &ref_content) < 0)
1020 ##### 24 continue;
1021 -
1022 - /* If the ref moved since we packed it, we must not delete it */
1023 312 25,26 if (!git_oid_equal(&current_id, &ref->oid))
1024 ##### 27 continue;
1025 -
1026 - /*
1027 - * if we fail to remove a single file, this is *not* good,
1028 - * but we should keep going and remove as many as possible.
1029 - * If we fail to remove, the ref is still in the old state, so
1030 - * we haven't lost information.
1031 - */
1032 312 28,29 p_unlink(lock.path_original);
1033 - }
1034 -
1035 38 34 git_buf_dispose(&ref_content);
1036 38 35 git_filebuf_cleanup(&lock);
1037 38 36 return 0;
1038 - }
1039 -
1040 - /*
1041 - * Write all the contents in the in-memory packfile to disk.
1042 - */
1043 64 2 static int packed_write(refdb_fs_backend *backend)
1044 - {
1045 64 2 git_sortedcache *refcache = backend->refcache;
1046 64 2 git_filebuf pack_file = GIT_FILEBUF_INIT;
1047 64 2 int error, open_flags = 0;
1048 - size_t i;
1049 -
1050 - /* lock the cache to updates while we do this */
1051 64 2,3 if ((error = git_sortedcache_wlock(refcache)) < 0)
1052 ##### 4 return error;
1053 -
1054 64 5 if (backend->fsync)
1055 2 6 open_flags = GIT_FILEBUF_FSYNC;
1056 -
1057 - /* Open the file! */
1058 64 7-9 if ((error = git_filebuf_open(&pack_file, git_sortedcache_path(refcache), open_flags, GIT_PACKEDREFS_FILE_MODE)) < 0)
1059 18 10 goto fail;
1060 -
1061 - /* Packfiles have a header... apparently
1062 - * This is in fact not required, but we might as well print it
1063 - * just for kicks */
1064 46 11,12 if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < 0)
1065 ##### 13 goto fail;
1066 -
1067 2011 14,24-26 for (i = 0; i < git_sortedcache_entrycount(refcache); ++i) {
1068 1965 15 struct packref *ref = git_sortedcache_entry(refcache, i);
1069 1965 16,17 assert(ref);
1070 -
1071 1965 18,19 if ((error = packed_find_peel(backend, ref)) < 0)
1072 ##### 20 goto fail;
1073 -
1074 1965 21,22 if ((error = packed_write_ref(ref, &pack_file)) < 0)
1075 ##### 23 goto fail;
1076 - }
1077 -
1078 - /* if we've written all the references properly, we can commit
1079 - * the packfile to make the changes effective */
1080 46 27,28 if ((error = git_filebuf_commit(&pack_file)) < 0)
1081 ##### 29 goto fail;
1082 -
1083 - /* when and only when the packfile has been properly written,
1084 - * we can go ahead and remove the loose refs */
1085 46 30,31 if ((error = packed_remove_loose(backend)) < 0)
1086 8 32 goto fail;
1087 -
1088 38 33 git_sortedcache_updated(refcache);
1089 38 34 git_sortedcache_wunlock(refcache);
1090 -
1091 - /* we're good now */
1092 38 35 return 0;
1093 -
1094 - fail:
1095 26 36 git_filebuf_cleanup(&pack_file);
1096 26 37 git_sortedcache_wunlock(refcache);
1097 -
1098 26 38 return error;
1099 - }
1100 -
1101 151 2 static int packed_delete(refdb_fs_backend *backend, const char *ref_name)
1102 - {
1103 - size_t pack_pos;
1104 151 2 int error, found = 0;
1105 -
1106 151 2,3 if ((error = packed_reload(backend)) < 0)
1107 ##### 4 goto cleanup;
1108 -
1109 151 5,6 if ((error = git_sortedcache_wlock(backend->refcache)) < 0)
1110 ##### 7 goto cleanup;
1111 -
1112 - /* If a packed reference exists, remove it from the packfile and repack if necessary */
1113 151 8 error = git_sortedcache_lookup_index(&pack_pos, backend->refcache, ref_name);
1114 151 9 if (error == 0) {
1115 20 10 error = git_sortedcache_remove(backend->refcache, pack_pos);
1116 20 11 found = 1;
1117 - }
1118 151 12 if (error == GIT_ENOTFOUND)
1119 131 13 error = 0;
1120 -
1121 151 14 git_sortedcache_wunlock(backend->refcache);
1122 -
1123 151 15 if (found)
1124 20 16 error = packed_write(backend);
1125 -
1126 - cleanup:
1127 151 17 return error;
1128 - }
1129 -
1130 - static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *author, const char *message);
1131 - static int has_reflog(git_repository *repo, const char *name);
1132 -
1133 2060 2 static int should_write_reflog(int *write, git_repository *repo, const char *name)
1134 - {
1135 - int error, logall;
1136 -
1137 2060 2 error = git_repository__configmap_lookup(&logall, repo, GIT_CONFIGMAP_LOGALLREFUPDATES);
1138 2060 3 if (error < 0)
1139 ##### 4 return error;
1140 -
1141 - /* Defaults to the opposite of the repo being bare */
1142 2060 5 if (logall == GIT_LOGALLREFUPDATES_UNSET)
1143 270 6,7 logall = !git_repository_is_bare(repo);
1144 -
1145 2060 8 *write = 0;
1146 2060 8 switch (logall) {
1147 - case GIT_LOGALLREFUPDATES_FALSE:
1148 251 9 *write = 0;
1149 251 9 break;
1150 -
1151 - case GIT_LOGALLREFUPDATES_TRUE:
1152 - /* Only write if it already has a log,
1153 - * or if it's under heads/, remotes/ or notes/
1154 - */
1155 1808 10,13,21 *write = has_reflog(repo, name) ||
1156 1471 12,14 !git__prefixcmp(name, GIT_REFS_HEADS_DIR) ||
1157 884 14,16 !git__strcmp(name, GIT_HEAD_FILE) ||
1158 1808 11,15,18-20 !git__prefixcmp(name, GIT_REFS_REMOTES_DIR) ||
1159 369 17 !git__prefixcmp(name, GIT_REFS_NOTES_DIR);
1160 1808 21 break;
1161 -
1162 - case GIT_LOGALLREFUPDATES_ALWAYS:
1163 1 22 *write = 1;
1164 1 22 break;
1165 - }
1166 -
1167 2060 23 return 0;
1168 - }
1169 -
1170 4593 2 static int cmp_old_ref(int *cmp, git_refdb_backend *backend, const char *name,
1171 - const git_oid *old_id, const char *old_target)
1172 - {
1173 4593 2 int error = 0;
1174 4593 2 git_reference *old_ref = NULL;
1175 -
1176 4593 2 *cmp = 0;
1177 - /* It "matches" if there is no old value to compare against */
1178 4593 2,3 if (!old_id && !old_target)
1179 2017 4 return 0;
1180 -
1181 2576 5,6 if ((error = refdb_fs_backend__lookup(&old_ref, backend, name)) < 0)
1182 1625 7 goto out;
1183 -
1184 - /* If the types don't match, there's no way the values do */
1185 951 8,9 if (old_id && old_ref->type != GIT_REFERENCE_DIRECT) {
1186 88 10 *cmp = -1;
1187 88 10 goto out;
1188 - }
1189 863 11,12 if (old_target && old_ref->type != GIT_REFERENCE_SYMBOLIC) {
1190 22 13 *cmp = 1;
1191 22 13 goto out;
1192 - }
1193 -
1194 841 14,15 if (old_id && old_ref->type == GIT_REFERENCE_DIRECT)
1195 693 16,17 *cmp = git_oid_cmp(old_id, &old_ref->target.oid);
1196 -
1197 841 18,19 if (old_target && old_ref->type == GIT_REFERENCE_SYMBOLIC)
1198 148 20 *cmp = git__strcmp(old_target, old_ref->target.symbolic);
1199 -
1200 - out:
1201 2576 21 git_reference_free(old_ref);
1202 -
1203 2576 22 return error;
1204 - }
1205 -
1206 - /*
1207 - * The git.git comment regarding this, for your viewing pleasure:
1208 - *
1209 - * Special hack: If a branch is updated directly and HEAD
1210 - * points to it (may happen on the remote side of a push
1211 - * for example) then logically the HEAD reflog should be
1212 - * updated too.
1213 - * A generic solution implies reverse symref information,
1214 - * but finding all symrefs pointing to the given branch
1215 - * would be rather costly for this rare event (the direct
1216 - * update of a branch) to be worth it. So let's cheat and
1217 - * check with HEAD only which should cover 99% of all usage
1218 - * scenarios (even 100% of the default ones).
1219 - */
1220 1464 2 static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref, const git_signature *who, const char *message)
1221 - {
1222 - int error;
1223 - git_oid old_id;
1224 1464 2 git_reference *tmp = NULL, *head = NULL, *peeled = NULL;
1225 - const char *name;
1226 -
1227 1464 2 if (ref->type == GIT_REFERENCE_SYMBOLIC)
1228 211 3 return 0;
1229 -
1230 - /* if we can't resolve, we use {0}*40 as old id */
1231 1253 4,5 if (git_reference_name_to_id(&old_id, backend->repo, ref->name) < 0)
1232 934 6 memset(&old_id, 0, sizeof(old_id));
1233 -
1234 1253 7,8 if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0)
1235 ##### 9 return error;
1236 -
1237 1253 10,11 if (git_reference_type(head) == GIT_REFERENCE_DIRECT)
1238 63 12 goto cleanup;
1239 -
1240 1190 13,14 if ((error = git_reference_lookup(&tmp, backend->repo, GIT_HEAD_FILE)) < 0)
1241 ##### 15 goto cleanup;
1242 -
1243 - /* Go down the symref chain until we find the branch */
1244 1844 16,23,24 while (git_reference_type(tmp) == GIT_REFERENCE_SYMBOLIC) {
1245 1192 17,18 error = git_reference_lookup(&peeled, backend->repo, git_reference_symbolic_target(tmp));
1246 1192 19 if (error < 0)
1247 538 20 break;
1248 -
1249 654 21 git_reference_free(tmp);
1250 654 22 tmp = peeled;
1251 - }
1252 -
1253 1190 25 if (error == GIT_ENOTFOUND) {
1254 538 26 error = 0;
1255 538 26 name = git_reference_symbolic_target(tmp);
1256 652 27 } else if (error < 0) {
1257 ##### 28 goto cleanup;
1258 - } else {
1259 652 29 name = git_reference_name(tmp);
1260 - }
1261 -
1262 1190 30 if (strcmp(name, ref->name))
1263 950 31 goto cleanup;
1264 -
1265 240 32,33 error = reflog_append(backend, head, &old_id, git_reference_target(ref), who, message);
1266 -
1267 - cleanup:
1268 1253 34 git_reference_free(tmp);
1269 1253 35 git_reference_free(head);
1270 1253 36 return error;
1271 - }
1272 -
1273 2226 2 static int refdb_fs_backend__write(
1274 - git_refdb_backend *_backend,
1275 - const git_reference *ref,
1276 - int force,
1277 - const git_signature *who,
1278 - const char *message,
1279 - const git_oid *old_id,
1280 - const char *old_target)
1281 - {
1282 2226 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
1283 2226 2 git_filebuf file = GIT_FILEBUF_INIT;
1284 2226 2 int error = 0;
1285 -
1286 2226 2,3 assert(backend);
1287 -
1288 2226 4,5 if ((error = reference_path_available(backend, ref->name, NULL, force)) < 0)
1289 10 6 return error;
1290 -
1291 - /* We need to perform the reflog append and old value check under the ref's lock */
1292 2216 7,8 if ((error = loose_lock(&file, backend, ref->name)) < 0)
1293 4 9 return error;
1294 -
1295 2212 10 return refdb_fs_backend__write_tail(_backend, ref, &file, true, old_id, old_target, who, message);
1296 - }
1297 -
1298 2222 2 static int refdb_fs_backend__write_tail(
1299 - git_refdb_backend *_backend,
1300 - const git_reference *ref,
1301 - git_filebuf *file,
1302 - int update_reflog,
1303 - const git_oid *old_id,
1304 - const char *old_target,
1305 - const git_signature *who,
1306 - const char *message)
1307 - {
1308 2222 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
1309 2222 2 int error = 0, cmp = 0, should_write;
1310 2222 2 const char *new_target = NULL;
1311 2222 2 const git_oid *new_id = NULL;
1312 -
1313 2222 2,3 if ((error = cmp_old_ref(&cmp, _backend, ref->name, old_id, old_target)) < 0)
1314 ##### 4 goto on_error;
1315 -
1316 2222 5 if (cmp) {
1317 6 6 git_error_set(GIT_ERROR_REFERENCE, "old reference value does not match");
1318 6 7 error = GIT_EMODIFIED;
1319 6 7 goto on_error;
1320 - }
1321 -
1322 2216 8 if (ref->type == GIT_REFERENCE_SYMBOLIC)
1323 271 9 new_target = ref->target.symbolic;
1324 - else
1325 1945 10 new_id = &ref->target.oid;
1326 -
1327 2216 11 error = cmp_old_ref(&cmp, _backend, ref->name, new_id, new_target);
1328 2216 12,13 if (error < 0 && error != GIT_ENOTFOUND)
1329 ##### 14 goto on_error;
1330 -
1331 - /* Don't update if we have the same value */
1332 2216 15,16 if (!error && !cmp) {
1333 151 17 error = 0;
1334 151 17 goto on_error; /* not really error */
1335 - }
1336 -
1337 2065 18 if (update_reflog) {
1338 2060 19,20 if ((error = should_write_reflog(&should_write, backend->repo, ref->name)) < 0)
1339 ##### 21 goto on_error;
1340 -
1341 2060 22 if (should_write) {
1342 1465 23,24 if ((error = reflog_append(backend, ref, NULL, NULL, who, message)) < 0)
1343 1 25 goto on_error;
1344 1464 26,27 if ((error = maybe_append_head(backend, ref, who, message)) < 0)
1345 ##### 28 goto on_error;
1346 - }
1347 - }
1348 -
1349 2064 29 return loose_commit(file, ref);
1350 -
1351 - on_error:
1352 158 30 git_filebuf_cleanup(file);
1353 158 31 return error;
1354 - }
1355 -
1356 223 2 static void refdb_fs_backend__prune_refs(
1357 - refdb_fs_backend *backend,
1358 - const char *ref_name,
1359 - const char *prefix)
1360 - {
1361 223 2 git_buf relative_path = GIT_BUF_INIT;
1362 223 2 git_buf base_path = GIT_BUF_INIT;
1363 - size_t commonlen;
1364 -
1365 223 2-4 assert(backend && ref_name);
1366 -
1367 223 5,6 if (git_buf_sets(&relative_path, ref_name) < 0)
1368 ##### 7 goto cleanup;
1369 -
1370 223 8 git_path_squash_slashes(&relative_path);
1371 223 9-11,13,14 if ((commonlen = git_path_common_dirlen("refs/heads/", git_buf_cstr(&relative_path))) == strlen("refs/heads/") ||
1372 78 12,16,17 (commonlen = git_path_common_dirlen("refs/tags/", git_buf_cstr(&relative_path))) == strlen("refs/tags/") ||
1373 51 15 (commonlen = git_path_common_dirlen("refs/remotes/", git_buf_cstr(&relative_path))) == strlen("refs/remotes/")) {
1374 -
1375 216 18 git_buf_truncate(&relative_path, commonlen);
1376 -
1377 216 19 if (prefix) {
1378 216 20-22 if (git_buf_join3(&base_path, '/', backend->commonpath, prefix, git_buf_cstr(&relative_path)) < 0)
1379 ##### 23 goto cleanup;
1380 - } else {
1381 ##### 24-26 if (git_buf_joinpath(&base_path, backend->commonpath, git_buf_cstr(&relative_path)) < 0)
1382 ##### 27 goto cleanup;
1383 - }
1384 -
1385 216 28,29 git_futils_rmdir_r(ref_name + commonlen, git_buf_cstr(&base_path), GIT_RMDIR_EMPTY_PARENTS | GIT_RMDIR_SKIP_ROOT);
1386 - }
1387 -
1388 - cleanup:
1389 223 30 git_buf_dispose(&relative_path);
1390 223 31 git_buf_dispose(&base_path);
1391 223 32 }
1392 -
1393 150 2 static int refdb_fs_backend__delete(
1394 - git_refdb_backend *_backend,
1395 - const char *ref_name,
1396 - const git_oid *old_id, const char *old_target)
1397 - {
1398 150 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
1399 150 2 git_filebuf file = GIT_FILEBUF_INIT;
1400 150 2 int error = 0;
1401 -
1402 150 2-4 assert(backend && ref_name);
1403 -
1404 150 5,6 if ((error = loose_lock(&file, backend, ref_name)) < 0)
1405 ##### 7 return error;
1406 -
1407 150 8,9 if ((error = refdb_reflog_fs__delete(_backend, ref_name)) < 0) {
1408 ##### 10 git_filebuf_cleanup(&file);
1409 ##### 11 return error;
1410 - }
1411 -
1412 150 12 return refdb_fs_backend__delete_tail(_backend, &file, ref_name, old_id, old_target);
1413 - }
1414 -
1415 150 2 static int loose_delete(refdb_fs_backend *backend, const char *ref_name)
1416 - {
1417 150 2 git_buf loose_path = GIT_BUF_INIT;
1418 150 2 int error = 0;
1419 -
1420 150 2,3 if (git_buf_joinpath(&loose_path, backend->commonpath, ref_name) < 0)
1421 ##### 4 return -1;
1422 -
1423 150 5 error = p_unlink(loose_path.ptr);
1424 150 6-8 if (error < 0 && errno == ENOENT)
1425 13 9 error = GIT_ENOTFOUND;
1426 137 10 else if (error != 0)
1427 ##### 11 error = -1;
1428 -
1429 150 12 git_buf_dispose(&loose_path);
1430 -
1431 150 13 return error;
1432 - }
1433 -
1434 155 2 static int refdb_fs_backend__delete_tail(
1435 - git_refdb_backend *_backend,
1436 - git_filebuf *file,
1437 - const char *ref_name,
1438 - const git_oid *old_id, const char *old_target)
1439 - {
1440 155 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
1441 155 2 int error = 0, cmp = 0;
1442 155 2 bool packed_deleted = 0;
1443 -
1444 155 2 error = cmp_old_ref(&cmp, _backend, ref_name, old_id, old_target);
1445 155 3 if (error < 0)
1446 ##### 4 goto cleanup;
1447 -
1448 155 5 if (cmp) {
1449 4 6 git_error_set(GIT_ERROR_REFERENCE, "old reference value does not match");
1450 4 7 error = GIT_EMODIFIED;
1451 4 7 goto cleanup;
1452 - }
1453 -
1454 - /*
1455 - * To ensure that an external observer will see either the current ref value
1456 - * (because the loose ref still exists), or a missing ref (after the packed-file is
1457 - * unlocked, there will be nothing left), we must ensure things happen in the
1458 - * following order:
1459 - *
1460 - * - the packed-ref file is locked and loaded, as well as a loose one, if it exists
1461 - * - we optimistically delete a packed ref, keeping track of whether it existed
1462 - * - we delete the loose ref, note that we have its .lock
1463 - * - the loose ref is "unlocked", then the packed-ref file is rewritten and unlocked
1464 - * - we should prune the path components if a loose ref was deleted
1465 - *
1466 - * Note that, because our packed backend doesn't expose its filesystem lock,
1467 - * we might not be able to guarantee that this is what actually happens (ie.
1468 - * as our current code never write packed-refs.lock, nothing stops observers
1469 - * from grabbing a "stale" value from there).
1470 - */
1471 151 8-10 if ((error = packed_delete(backend, ref_name)) < 0 && error != GIT_ENOTFOUND)
1472 1 11 goto cleanup;
1473 -
1474 150 12 if (error == 0)
1475 150 13 packed_deleted = 1;
1476 -
1477 150 14-16 if ((error = loose_delete(backend, ref_name)) < 0 && error != GIT_ENOTFOUND)
1478 ##### 17 goto cleanup;
1479 -
1480 150 18 if (error == GIT_ENOTFOUND) {
1481 13 19-21 error = packed_deleted ? 0 : ref_error_notfound(ref_name);
1482 13 22 goto cleanup;
1483 - }
1484 -
1485 - cleanup:
1486 155 23 git_filebuf_cleanup(file);
1487 155 24 if (error == 0)
1488 150 25 refdb_fs_backend__prune_refs(backend, ref_name, "");
1489 155 26 return error;
1490 - }
1491 -
1492 - static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_name, const char *new_name);
1493 -
1494 42 2 static int refdb_fs_backend__rename(
1495 - git_reference **out,
1496 - git_refdb_backend *_backend,
1497 - const char *old_name,
1498 - const char *new_name,
1499 - int force,
1500 - const git_signature *who,
1501 - const char *message)
1502 - {
1503 42 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
1504 42 2 git_reference *old, *new = NULL;
1505 42 2 git_filebuf file = GIT_FILEBUF_INIT;
1506 - int error;
1507 -
1508 42 2,3 assert(backend);
1509 -
1510 42 4,5 if ((error = reference_path_available(
1511 37 6,7 backend, new_name, old_name, force)) < 0 ||
1512 - (error = refdb_fs_backend__lookup(&old, _backend, old_name)) < 0)
1513 5 8 return error;
1514 -
1515 37 9,10 if ((error = refdb_fs_backend__delete(_backend, old_name, NULL, NULL)) < 0) {
1516 ##### 11 git_reference_free(old);
1517 ##### 12 return error;
1518 - }
1519 -
1520 37 13 new = git_reference__realloc(&old, new_name);
1521 37 14 if (!new) {
1522 ##### 15 git_reference_free(old);
1523 ##### 16 return -1;
1524 - }
1525 -
1526 37 17,18 if ((error = loose_lock(&file, backend, new->name)) < 0) {
1527 ##### 19 git_reference_free(new);
1528 ##### 20 return error;
1529 - }
1530 -
1531 - /* Try to rename the refog; it's ok if the old doesn't exist */
1532 37 21 error = refdb_reflog_fs__rename(_backend, old_name, new_name);
1533 37 22,23,25,26 if (((error == 0) || (error == GIT_ENOTFOUND)) &&
1534 37 24 ((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0)) {
1535 ##### 27 git_reference_free(new);
1536 ##### 28 git_filebuf_cleanup(&file);
1537 ##### 29 return error;
1538 - }
1539 -
1540 37 30 if (error < 0) {
1541 ##### 31 git_reference_free(new);
1542 ##### 32 git_filebuf_cleanup(&file);
1543 ##### 33 return error;
1544 - }
1545 -
1546 -
1547 37 34-36 if ((error = loose_commit(&file, new)) < 0 || out == NULL) {
1548 ##### 37 git_reference_free(new);
1549 ##### 38 return error;
1550 - }
1551 -
1552 37 39 *out = new;
1553 37 39 return 0;
1554 - }
1555 -
1556 44 2 static int refdb_fs_backend__compress(git_refdb_backend *_backend)
1557 - {
1558 - int error;
1559 44 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
1560 -
1561 44 2,3 assert(backend);
1562 -
1563 44 4-7 if ((error = packed_reload(backend)) < 0 || /* load the existing packfile */
1564 44 8,9 (error = packed_loadloose(backend)) < 0 || /* add all the loose refs */
1565 - (error = packed_write(backend)) < 0) /* write back to disk */
1566 25 10 return error;
1567 -
1568 19 11 return 0;
1569 - }
1570 -
1571 2167 2 static void refdb_fs_backend__free(git_refdb_backend *_backend)
1572 - {
1573 2167 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
1574 -
1575 2167 2,3 assert(backend);
1576 -
1577 2167 4 git_sortedcache_free(backend->refcache);
1578 2167 5 git__free(backend->gitpath);
1579 2167 6 git__free(backend->commonpath);
1580 2167 7 git__free(backend);
1581 2167 8 }
1582 -
1583 4332 2 static char *setup_namespace(git_repository *repo, const char *in)
1584 - {
1585 4332 2 git_buf path = GIT_BUF_INIT;
1586 4332 2 char *parts, *start, *end, *out = NULL;
1587 -
1588 4332 2 if (!in)
1589 ##### 3 goto done;
1590 -
1591 4332 4 git_buf_puts(&path, in);
1592 -
1593 - /* if the repo is not namespaced, nothing else to do */
1594 4332 5 if (repo->namespace == NULL) {
1595 4330 6 out = git_buf_detach(&path);
1596 4330 7 goto done;
1597 - }
1598 -
1599 2 8 parts = end = git__strdup(repo->namespace);
1600 2 9 if (parts == NULL)
1601 ##### 10 goto done;
1602 -
1603 - /*
1604 - * From `man gitnamespaces`:
1605 - * namespaces which include a / will expand to a hierarchy
1606 - * of namespaces; for example, GIT_NAMESPACE=foo/bar will store
1607 - * refs under refs/namespaces/foo/refs/namespaces/bar/
1608 - */
1609 2 11,13,14 while ((start = git__strsep(&end, "/")) != NULL)
1610 ##### 12 git_buf_printf(&path, "refs/namespaces/%s/", start);
1611 -
1612 2 15 git_buf_printf(&path, "refs/namespaces/%s/refs", end);
1613 2 16 git__free(parts);
1614 -
1615 - /* Make sure that the folder with the namespace exists */
1616 2 17-19 if (git_futils_mkdir_relative(git_buf_cstr(&path), in, 0777,
1617 - GIT_MKDIR_PATH, NULL) < 0)
1618 ##### 20 goto done;
1619 -
1620 - /* Return root of the namespaced gitpath, i.e. without the trailing '/refs' */
1621 2 21 git_buf_rtruncate_at_char(&path, '/');
1622 2 22 out = git_buf_detach(&path);
1623 -
1624 - done:
1625 4332 23 git_buf_dispose(&path);
1626 4332 24 return out;
1627 - }
1628 -
1629 197 2 static int reflog_alloc(git_reflog **reflog, const char *name)
1630 - {
1631 - git_reflog *log;
1632 -
1633 197 2 *reflog = NULL;
1634 -
1635 197 2 log = git__calloc(1, sizeof(git_reflog));
1636 197 3,4 GIT_ERROR_CHECK_ALLOC(log);
1637 -
1638 197 5 log->ref_name = git__strdup(name);
1639 197 6,7 GIT_ERROR_CHECK_ALLOC(log->ref_name);
1640 -
1641 197 8,9 if (git_vector_init(&log->entries, 0, NULL) < 0) {
1642 ##### 10 git__free(log->ref_name);
1643 ##### 11 git__free(log);
1644 ##### 12 return -1;
1645 - }
1646 -
1647 197 13 *reflog = log;
1648 -
1649 197 13 return 0;
1650 - }
1651 -
1652 197 2 static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size)
1653 - {
1654 197 2 git_parse_ctx parser = GIT_PARSE_CTX_INIT;
1655 -
1656 197 2,3 if ((git_parse_ctx_init(&parser, buf, buf_size)) < 0)
1657 ##### 4 return -1;
1658 -
1659 943 5,42,43 for (; parser.remain_len; git_parse_advance_line(&parser)) {
1660 - git_reflog_entry *entry;
1661 - const char *sig;
1662 - char c;
1663 -
1664 746 6 entry = git__calloc(1, sizeof(*entry));
1665 746 7,8,41 GIT_ERROR_CHECK_ALLOC(entry);
1666 746 9 entry->committer = git__calloc(1, sizeof(*entry->committer));
1667 746 10,11 GIT_ERROR_CHECK_ALLOC(entry->committer);
1668 -
1669 746 12,13,15 if (git_parse_advance_oid(&entry->oid_old, &parser) < 0 ||
1670 745 14,17 git_parse_advance_expected(&parser, " ", 1) < 0 ||
1671 745 16 git_parse_advance_oid(&entry->oid_cur, &parser) < 0)
1672 - goto next;
1673 -
1674 745 18 sig = parser.line;
1675 35343 18,20-23 while (git_parse_peek(&c, &parser, 0) == 0 && c != '\t' && c != '\n')
1676 34598 19 git_parse_advance_chars(&parser, 1);
1677 -
1678 745 24,25 if (git_signature__parse(entry->committer, &sig, parser.line, NULL, 0) < 0)
1679 ##### 26 goto next;
1680 -
1681 745 27 if (c == '\t') {
1682 - size_t len;
1683 741 28 git_parse_advance_chars(&parser, 1);
1684 -
1685 741 29 len = parser.line_len;
1686 741 29 if (parser.line[len - 1] == '\n')
1687 741 30 len--;
1688 -
1689 741 31 entry->msg = git__strndup(parser.line, len);
1690 741 32,33 GIT_ERROR_CHECK_ALLOC(entry->msg);
1691 - }
1692 -
1693 745 34,35 if ((git_vector_insert(&log->entries, entry)) < 0) {
1694 ##### 36 git_reflog_entry__free(entry);
1695 ##### 37 return -1;
1696 - }
1697 -
1698 745 38 continue;
1699 -
1700 - next:
1701 1 39,40 git_reflog_entry__free(entry);
1702 - }
1703 -
1704 197 44 return 0;
1705 - }
1706 -
1707 68 2 static int create_new_reflog_file(const char *filepath)
1708 - {
1709 - int fd, error;
1710 -
1711 68 2,3 if ((error = git_futils_mkpath2file(filepath, GIT_REFLOG_DIR_MODE)) < 0)
1712 ##### 4 return error;
1713 -
1714 68 5,6 if ((fd = p_open(filepath,
1715 - O_WRONLY | O_CREAT,
1716 - GIT_REFLOG_FILE_MODE)) < 0)
1717 ##### 7 return -1;
1718 -
1719 68 8 return p_close(fd);
1720 - }
1721 -
1722 3844 2 GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name)
1723 - {
1724 3844 2 if (strcmp(name, GIT_HEAD_FILE) == 0)
1725 762 3 return git_buf_join3(path, '/', repo->gitdir, GIT_REFLOG_DIR, name);
1726 3082 4 return git_buf_join3(path, '/', repo->commondir, GIT_REFLOG_DIR, name);
1727 - }
1728 -
1729 61 2 static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name)
1730 - {
1731 - refdb_fs_backend *backend;
1732 - git_repository *repo;
1733 61 2 git_buf path = GIT_BUF_INIT;
1734 - int error;
1735 -
1736 61 2-4 assert(_backend && name);
1737 -
1738 61 5 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
1739 61 5 repo = backend->repo;
1740 -
1741 61 5,6 if ((error = retrieve_reflog_path(&path, repo, name)) < 0)
1742 ##### 7 return error;
1743 -
1744 61 8,9 error = create_new_reflog_file(git_buf_cstr(&path));
1745 61 10 git_buf_dispose(&path);
1746 -
1747 61 11 return error;
1748 - }
1749 -
1750 1816 2 static int has_reflog(git_repository *repo, const char *name)
1751 - {
1752 1816 2 int ret = 0;
1753 1816 2 git_buf path = GIT_BUF_INIT;
1754 -
1755 1816 2,3 if (retrieve_reflog_path(&path, repo, name) < 0)
1756 ##### 4 goto cleanup;
1757 -
1758 1816 5-7 ret = git_path_isfile(git_buf_cstr(&path));
1759 -
1760 - cleanup:
1761 1816 8 git_buf_dispose(&path);
1762 1816 9 return ret;
1763 - }
1764 -
1765 8 2 static int refdb_reflog_fs__has_log(git_refdb_backend *_backend, const char *name)
1766 - {
1767 - refdb_fs_backend *backend;
1768 -
1769 8 2-4 assert(_backend && name);
1770 -
1771 8 5 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
1772 -
1773 8 5 return has_reflog(backend->repo, name);
1774 - }
1775 -
1776 197 2 static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend, const char *name)
1777 - {
1778 197 2 int error = -1;
1779 197 2 git_buf log_path = GIT_BUF_INIT;
1780 197 2 git_buf log_file = GIT_BUF_INIT;
1781 197 2 git_reflog *log = NULL;
1782 - git_repository *repo;
1783 - refdb_fs_backend *backend;
1784 -
1785 197 2-5 assert(out && _backend && name);
1786 -
1787 197 6 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
1788 197 6 repo = backend->repo;
1789 -
1790 197 6,7 if (reflog_alloc(&log, name) < 0)
1791 ##### 8 return -1;
1792 -
1793 197 9,10 if (retrieve_reflog_path(&log_path, repo, name) < 0)
1794 ##### 11 goto cleanup;
1795 -
1796 197 12,13 error = git_futils_readbuffer(&log_file, git_buf_cstr(&log_path));
1797 197 14,15 if (error < 0 && error != GIT_ENOTFOUND)
1798 ##### 16 goto cleanup;
1799 -
1800 197 17,19,20 if ((error == GIT_ENOTFOUND) &&
1801 7 18 ((error = create_new_reflog_file(git_buf_cstr(&log_path))) < 0))
1802 ##### 21 goto cleanup;
1803 -
1804 197 22-25 if ((error = reflog_parse(log,
1805 - git_buf_cstr(&log_file), git_buf_len(&log_file))) < 0)
1806 ##### 26 goto cleanup;
1807 -
1808 197 27 *out = log;
1809 197 27 goto success;
1810 -
1811 - cleanup:
1812 ##### 28 git_reflog_free(log);
1813 -
1814 - success:
1815 197 29 git_buf_dispose(&log_file);
1816 197 30 git_buf_dispose(&log_path);
1817 -
1818 197 31 return error;
1819 - }
1820 -
1821 1629 2 static int serialize_reflog_entry(
1822 - git_buf *buf,
1823 - const git_oid *oid_old,
1824 - const git_oid *oid_new,
1825 - const git_signature *committer,
1826 - const char *msg)
1827 - {
1828 - char raw_old[GIT_OID_HEXSZ+1];
1829 - char raw_new[GIT_OID_HEXSZ+1];
1830 -
1831 1629 2 git_oid_tostr(raw_old, GIT_OID_HEXSZ+1, oid_old);
1832 1629 3 git_oid_tostr(raw_new, GIT_OID_HEXSZ+1, oid_new);
1833 -
1834 1629 4 git_buf_clear(buf);
1835 -
1836 1629 5 git_buf_puts(buf, raw_old);
1837 1629 6 git_buf_putc(buf, ' ');
1838 1629 7 git_buf_puts(buf, raw_new);
1839 -
1840 1629 8 git_signature__writebuf(buf, " ", committer);
1841 -
1842 - /* drop trailing LF */
1843 1629 9 git_buf_rtrim(buf);
1844 -
1845 1629 10 if (msg) {
1846 - size_t i;
1847 -
1848 1274 11 git_buf_putc(buf, '\t');
1849 1274 12 git_buf_puts(buf, msg);
1850 -
1851 213490 13,16,17 for (i = 0; i < buf->size - 2; i++)
1852 212216 14 if (buf->ptr[i] == '\n')
1853 2 15 buf->ptr[i] = ' ';
1854 1274 18 git_buf_rtrim(buf);
1855 - }
1856 -
1857 1629 19 git_buf_putc(buf, '\n');
1858 -
1859 1629 20 return git_buf_oom(buf);
1860 - }
1861 -
1862 17 2 static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char *refname)
1863 - {
1864 - git_repository *repo;
1865 17 2 git_buf log_path = GIT_BUF_INIT;
1866 - int error;
1867 -
1868 17 2 repo = backend->repo;
1869 -
1870 17 2,3 if (!git_path_isvalid(backend->repo, refname, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
1871 ##### 4 git_error_set(GIT_ERROR_INVALID, "invalid reference name '%s'", refname);
1872 ##### 5 return GIT_EINVALIDSPEC;
1873 - }
1874 -
1875 17 6,7 if (retrieve_reflog_path(&log_path, repo, refname) < 0)
1876 ##### 8 return -1;
1877 -
1878 17 9-11 if (!git_path_isfile(git_buf_cstr(&log_path))) {
1879 1 12 git_error_set(GIT_ERROR_INVALID,
1880 - "log file for reference '%s' doesn't exist", refname);
1881 1 13 error = -1;
1882 1 13 goto cleanup;
1883 - }
1884 -
1885 16 14,15 error = git_filebuf_open(file, git_buf_cstr(&log_path), 0, GIT_REFLOG_FILE_MODE);
1886 -
1887 - cleanup:
1888 17 16 git_buf_dispose(&log_path);
1889 -
1890 17 17 return error;
1891 - }
1892 -
1893 17 2 static int refdb_reflog_fs__write(git_refdb_backend *_backend, git_reflog *reflog)
1894 - {
1895 17 2 int error = -1;
1896 - unsigned int i;
1897 - git_reflog_entry *entry;
1898 - refdb_fs_backend *backend;
1899 17 2 git_buf log = GIT_BUF_INIT;
1900 17 2 git_filebuf fbuf = GIT_FILEBUF_INIT;
1901 -
1902 17 2-4 assert(_backend && reflog);
1903 -
1904 17 5 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
1905 -
1906 17 5,6 if ((error = lock_reflog(&fbuf, backend, reflog->ref_name)) < 0)
1907 1 7 return -1;
1908 -
1909 42 8,15-17 git_vector_foreach(&reflog->entries, i, entry) {
1910 26 9,10 if (serialize_reflog_entry(&log, &(entry->oid_old), &(entry->oid_cur), entry->committer, entry->msg) < 0)
1911 ##### 11 goto cleanup;
1912 -
1913 26 12,13 if ((error = git_filebuf_write(&fbuf, log.ptr, log.size)) < 0)
1914 ##### 14 goto cleanup;
1915 - }
1916 -
1917 16 18 error = git_filebuf_commit(&fbuf);
1918 16 19 goto success;
1919 -
1920 - cleanup:
1921 ##### 20 git_filebuf_cleanup(&fbuf);
1922 -
1923 - success:
1924 16 21 git_buf_dispose(&log);
1925 -
1926 16 22 return error;
1927 - }
1928 -
1929 - /* Append to the reflog, must be called under reference lock */
1930 1742 2 static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *who, const char *message)
1931 - {
1932 - int error, is_symbolic, open_flags;
1933 1742 2 git_oid old_id = {{0}}, new_id = {{0}};
1934 1742 2 git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
1935 1742 2 git_repository *repo = backend->repo;
1936 -
1937 1742 2 is_symbolic = ref->type == GIT_REFERENCE_SYMBOLIC;
1938 -
1939 - /* "normal" symbolic updates do not write */
1940 1742 2,3 if (is_symbolic &&
1941 453 3,4 strcmp(ref->name, GIT_HEAD_FILE) &&
1942 ##### 5 !(old && new))
1943 120 6 return 0;
1944 -
1945 - /* From here on is_symbolic also means that it's HEAD */
1946 -
1947 1622 7 if (old) {
1948 275 8 git_oid_cpy(&old_id, old);
1949 - } else {
1950 1347 9 error = git_reference_name_to_id(&old_id, repo, ref->name);
1951 1347 10,11 if (error < 0 && error != GIT_ENOTFOUND)
1952 ##### 12 return error;
1953 - }
1954 -
1955 1622 13 if (new) {
1956 240 14 git_oid_cpy(&new_id, new);
1957 - } else {
1958 1382 15 if (!is_symbolic) {
1959 1289 16,17 git_oid_cpy(&new_id, git_reference_target(ref));
1960 - } else {
1961 93 18,19 error = git_reference_name_to_id(&new_id, repo, git_reference_symbolic_target(ref));
1962 93 20,21 if (error < 0 && error != GIT_ENOTFOUND)
1963 ##### 22 return error;
1964 - /* detaching HEAD does not create an entry */
1965 93 23 if (error == GIT_ENOTFOUND)
1966 19 24 return 0;
1967 -
1968 74 25 git_error_clear();
1969 - }
1970 - }
1971 -
1972 1603 26,27 if ((error = serialize_reflog_entry(&buf, &old_id, &new_id, who, message)) < 0)
1973 ##### 28 goto cleanup;
1974 -
1975 1603 29,30 if ((error = retrieve_reflog_path(&path, repo, ref->name)) < 0)
1976 ##### 31 goto cleanup;
1977 -
1978 1603 32-35 if (((error = git_futils_mkpath2file(git_buf_cstr(&path), 0777)) < 0) &&
1979 - (error != GIT_EEXISTS)) {
1980 ##### 36 goto cleanup;
1981 - }
1982 -
1983 - /* If the new branch matches part of the namespace of a previously deleted branch,
1984 - * there maybe an obsolete/unused directory (or directory hierarchy) in the way.
1985 - */
1986 1603 37-39 if (git_path_isdir(git_buf_cstr(&path))) {
1987 1 40-42 if ((error = git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY)) < 0) {
1988 ##### 43 if (error == GIT_ENOTFOUND)
1989 ##### 44,45 error = 0;
1990 1 46-48 } else if (git_path_isdir(git_buf_cstr(&path))) {
1991 1 49 git_error_set(GIT_ERROR_REFERENCE, "cannot create reflog at '%s', there are reflogs beneath that folder",
1992 1 49 ref->name);
1993 1 50 error = GIT_EDIRECTORY;
1994 - }
1995 -
1996 1 51 if (error != 0)
1997 1 52 goto cleanup;
1998 - }
1999 -
2000 1602 53 open_flags = O_WRONLY | O_CREAT | O_APPEND;
2001 -
2002 1602 53 if (backend->fsync)
2003 2 54 open_flags |= O_FSYNC;
2004 -
2005 1602 55,56 error = git_futils_writebuffer(&buf, git_buf_cstr(&path), open_flags, GIT_REFLOG_FILE_MODE);
2006 -
2007 - cleanup:
2008 1603 57 git_buf_dispose(&buf);
2009 1603 58 git_buf_dispose(&path);
2010 -
2011 1603 59 return error;
2012 - }
2013 -
2014 38 2 static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_name, const char *new_name)
2015 - {
2016 38 2 int error = 0, fd;
2017 38 2 git_buf old_path = GIT_BUF_INIT;
2018 38 2 git_buf new_path = GIT_BUF_INIT;
2019 38 2 git_buf temp_path = GIT_BUF_INIT;
2020 38 2 git_buf normalized = GIT_BUF_INIT;
2021 - git_repository *repo;
2022 - refdb_fs_backend *backend;
2023 -
2024 38 2-5 assert(_backend && old_name && new_name);
2025 -
2026 38 6 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
2027 38 6 repo = backend->repo;
2028 -
2029 38 6,7 if ((error = git_reference__normalize_name(
2030 - &normalized, new_name, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL)) < 0)
2031 1 8 return error;
2032 -
2033 37 9,10 if (git_buf_joinpath(&temp_path, repo->gitdir, GIT_REFLOG_DIR) < 0)
2034 ##### 11 return -1;
2035 -
2036 37 12-14 if (git_buf_joinpath(&old_path, git_buf_cstr(&temp_path), old_name) < 0)
2037 ##### 15 return -1;
2038 -
2039 37 16-19 if (git_buf_joinpath(&new_path, git_buf_cstr(&temp_path), git_buf_cstr(&normalized)) < 0)
2040 ##### 20 return -1;
2041 -
2042 37 21-23 if (!git_path_exists(git_buf_cstr(&old_path))) {
2043 37 24 error = GIT_ENOTFOUND;
2044 37 24 goto cleanup;
2045 - }
2046 -
2047 - /*
2048 - * Move the reflog to a temporary place. This two-phase renaming is required
2049 - * in order to cope with funny renaming use cases when one tries to move a reference
2050 - * to a partially colliding namespace:
2051 - * - a/b -> a/b/c
2052 - * - a/b/c/d -> a/b/c
2053 - */
2054 ##### 25-27 if (git_buf_joinpath(&temp_path, git_buf_cstr(&temp_path), "temp_reflog") < 0)
2055 ##### 28 return -1;
2056 -
2057 ##### 29-31 if ((fd = git_futils_mktmp(&temp_path, git_buf_cstr(&temp_path), GIT_REFLOG_FILE_MODE)) < 0) {
2058 ##### 32 error = -1;
2059 ##### 32 goto cleanup;
2060 - }
2061 -
2062 ##### 33 p_close(fd);
2063 -
2064 ##### 34-37 if (p_rename(git_buf_cstr(&old_path), git_buf_cstr(&temp_path)) < 0) {
2065 ##### 38 git_error_set(GIT_ERROR_OS, "failed to rename reflog for %s", new_name);
2066 ##### 39 error = -1;
2067 ##### 39 goto cleanup;
2068 - }
2069 -
2070 ##### 40-42,45 if (git_path_isdir(git_buf_cstr(&new_path)) &&
2071 ##### 43,44 (git_futils_rmdir_r(git_buf_cstr(&new_path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) {
2072 ##### 46 error = -1;
2073 ##### 46 goto cleanup;
2074 - }
2075 -
2076 ##### 47-49 if (git_futils_mkpath2file(git_buf_cstr(&new_path), GIT_REFLOG_DIR_MODE) < 0) {
2077 ##### 50 error = -1;
2078 ##### 50 goto cleanup;
2079 - }
2080 -
2081 ##### 51-54 if (p_rename(git_buf_cstr(&temp_path), git_buf_cstr(&new_path)) < 0) {
2082 ##### 55 git_error_set(GIT_ERROR_OS, "failed to rename reflog for %s", new_name);
2083 ##### 56 error = -1;
2084 - }
2085 -
2086 - cleanup:
2087 37 57 git_buf_dispose(&temp_path);
2088 37 58 git_buf_dispose(&old_path);
2089 37 59 git_buf_dispose(&new_path);
2090 37 60 git_buf_dispose(&normalized);
2091 -
2092 37 61 return error;
2093 - }
2094 -
2095 150 2 static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name)
2096 - {
2097 150 2 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
2098 150 2 git_buf path = GIT_BUF_INIT;
2099 - int error;
2100 -
2101 150 2-4 assert(_backend && name);
2102 -
2103 150 5,6 if ((error = retrieve_reflog_path(&path, backend->repo, name)) < 0)
2104 ##### 7 goto out;
2105 -
2106 150 8,9 if (!git_path_exists(path.ptr))
2107 77 10 goto out;
2108 -
2109 73 11,12 if ((error = p_unlink(path.ptr)) < 0)
2110 ##### 13 goto out;
2111 -
2112 73 14 refdb_fs_backend__prune_refs(backend, name, GIT_REFLOG_DIR);
2113 -
2114 - out:
2115 150 15 git_buf_dispose(&path);
2116 -
2117 150 16 return error;
2118 - }
2119 -
2120 2167 2 int git_refdb_backend_fs(
2121 - git_refdb_backend **backend_out,
2122 - git_repository *repository)
2123 - {
2124 2167 2 int t = 0;
2125 2167 2 git_buf gitpath = GIT_BUF_INIT;
2126 - refdb_fs_backend *backend;
2127 -
2128 2167 2 backend = git__calloc(1, sizeof(refdb_fs_backend));
2129 2167 3,4 GIT_ERROR_CHECK_ALLOC(backend);
2130 -
2131 2167 5,6 if (git_refdb_init_backend(&backend->parent, GIT_REFDB_BACKEND_VERSION) < 0)
2132 ##### 7 goto fail;
2133 -
2134 2167 8 backend->repo = repository;
2135 -
2136 2167 8 if (repository->gitdir) {
2137 2166 9 backend->gitpath = setup_namespace(repository, repository->gitdir);
2138 -
2139 2166 10 if (backend->gitpath == NULL)
2140 ##### 11 goto fail;
2141 - }
2142 -
2143 2167 12 if (repository->commondir) {
2144 2166 13 backend->commonpath = setup_namespace(repository, repository->commondir);
2145 -
2146 2166 14 if (backend->commonpath == NULL)
2147 ##### 15 goto fail;
2148 - }
2149 -
2150 2167 16,17,20 if (git_buf_joinpath(&gitpath, backend->commonpath, GIT_PACKEDREFS_FILE) < 0 ||
2151 2167 18,19 git_sortedcache_new(
2152 - &backend->refcache, offsetof(struct packref, name),
2153 - NULL, NULL, packref_cmp, git_buf_cstr(&gitpath)) < 0)
2154 - goto fail;
2155 -
2156 2167 21 git_buf_dispose(&gitpath);
2157 -
2158 2167 22-24 if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_IGNORECASE) && t) {
2159 454 25 backend->iterator_flags |= GIT_ITERATOR_IGNORE_CASE;
2160 454 25 backend->direach_flags |= GIT_PATH_DIR_IGNORE_CASE;
2161 - }
2162 2167 26-28 if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_PRECOMPOSE) && t) {
2163 95 29 backend->iterator_flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE;
2164 95 29 backend->direach_flags |= GIT_PATH_DIR_PRECOMPOSE_UNICODE;
2165 - }
2166 2167 30-33 if ((!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_FSYNCOBJECTFILES) && t) ||
2167 - git_repository__fsync_gitdir)
2168 4 34 backend->fsync = 1;
2169 2167 35 backend->iterator_flags |= GIT_ITERATOR_DESCEND_SYMLINKS;
2170 -
2171 2167 35 backend->parent.exists = &refdb_fs_backend__exists;
2172 2167 35 backend->parent.lookup = &refdb_fs_backend__lookup;
2173 2167 35 backend->parent.iterator = &refdb_fs_backend__iterator;
2174 2167 35 backend->parent.write = &refdb_fs_backend__write;
2175 2167 35 backend->parent.del = &refdb_fs_backend__delete;
2176 2167 35 backend->parent.rename = &refdb_fs_backend__rename;
2177 2167 35 backend->parent.compress = &refdb_fs_backend__compress;
2178 2167 35 backend->parent.lock = &refdb_fs_backend__lock;
2179 2167 35 backend->parent.unlock = &refdb_fs_backend__unlock;
2180 2167 35 backend->parent.has_log = &refdb_reflog_fs__has_log;
2181 2167 35 backend->parent.ensure_log = &refdb_reflog_fs__ensure_log;
2182 2167 35 backend->parent.free = &refdb_fs_backend__free;
2183 2167 35 backend->parent.reflog_read = &refdb_reflog_fs__read;
2184 2167 35 backend->parent.reflog_write = &refdb_reflog_fs__write;
2185 2167 35 backend->parent.reflog_rename = &refdb_reflog_fs__rename;
2186 2167 35 backend->parent.reflog_delete = &refdb_reflog_fs__delete;
2187 -
2188 2167 35 *backend_out = (git_refdb_backend *)backend;
2189 2167 35 return 0;
2190 -
2191 - fail:
2192 ##### 36 git_buf_dispose(&gitpath);
2193 ##### 37 git__free(backend->gitpath);
2194 ##### 38 git__free(backend->commonpath);
2195 ##### 39 git__free(backend);
2196 ##### 40 return -1;
2197 - }