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 -
10 - #include "hash.h"
11 - #include "repository.h"
12 - #include "futils.h"
13 - #include "filebuf.h"
14 - #include "pack.h"
15 - #include "reflog.h"
16 - #include "refdb.h"
17 -
18 - #include <git2/tag.h>
19 - #include <git2/object.h>
20 - #include <git2/oid.h>
21 - #include <git2/branch.h>
22 - #include <git2/refs.h>
23 - #include <git2/refdb.h>
24 - #include <git2/sys/refs.h>
25 - #include <git2/signature.h>
26 - #include <git2/commit.h>
27 -
28 - bool git_reference__enable_symbolic_ref_target_validation = true;
29 -
30 - #define DEFAULT_NESTING_LEVEL 5
31 - #define MAX_NESTING_LEVEL 10
32 -
33 - enum {
34 - GIT_PACKREF_HAS_PEEL = 1,
35 - GIT_PACKREF_WAS_LOOSE = 2
36 - };
37 -
38 - 2 suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files)static git_reference *alloc_ref(const char *name)
39 - {
40 - 2 suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) git_reference *ref = NULL;
41 - 2 suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) size_t namelen = strlen(name), reflen;
42 -
43 - 2-7,9,11-13 suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) &&
44 - 8,10,14,15 suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) &&
45 - 14 suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) (ref = git__calloc(1, reflen)) != NULL)
46 - 16 suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) memcpy(ref->name, name, namelen + 1);
47 -
48 - 17 suppressed: function cannot be solved alloc_ref (automatic due to inconsistent arc counts in .gcda files) return ref;
49 - }
50 -
51 8844 2 git_reference *git_reference__alloc_symbolic(
52 - const char *name, const char *target)
53 - {
54 - git_reference *ref;
55 -
56 8844 2-4 assert(name && target);
57 -
58 8844 5 ref = alloc_ref(name);
59 8844 6 if (!ref)
60 ##### 7 return NULL;
61 -
62 8844 8 ref->type = GIT_REFERENCE_SYMBOLIC;
63 -
64 8844 8,9 if ((ref->target.symbolic = git__strdup(target)) == NULL) {
65 ##### 10 git__free(ref);
66 ##### 11 return NULL;
67 - }
68 -
69 8844 12 return ref;
70 - }
71 -
72 - 2 suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files)git_reference *git_reference__alloc(
73 - const char *name,
74 - const git_oid *oid,
75 - const git_oid *peel)
76 - {
77 - git_reference *ref;
78 -
79 - 2-4 suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) assert(name && oid);
80 -
81 - 5 suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) ref = alloc_ref(name);
82 - 6 suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) if (!ref)
83 - 7 suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) return NULL;
84 -
85 - 8 suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) ref->type = GIT_REFERENCE_DIRECT;
86 - 8 suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) git_oid_cpy(&ref->target.oid, oid);
87 -
88 - 9 suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) if (peel != NULL)
89 - 10 suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) git_oid_cpy(&ref->peel, peel);
90 -
91 - 11 suppressed: function cannot be solved git_reference__alloc (automatic due to inconsistent arc counts in .gcda files) return ref;
92 - }
93 -
94 38 2 git_reference *git_reference__realloc(
95 - git_reference **ptr_to_ref, const char *name)
96 - {
97 - size_t namelen, reflen;
98 38 2 git_reference *rewrite = NULL;
99 -
100 38 2-4 assert(ptr_to_ref && name);
101 -
102 38 5 namelen = strlen(name);
103 -
104 38 5-10,12,14-16 if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) &&
105 38 11,13,17,18 !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) &&
106 38 17 (rewrite = git__realloc(*ptr_to_ref, reflen)) != NULL)
107 38 19 memcpy(rewrite->name, name, namelen + 1);
108 -
109 38 20 *ptr_to_ref = NULL;
110 -
111 38 20 return rewrite;
112 - }
113 -
114 3 2 int git_reference_dup(git_reference **dest, git_reference *source)
115 - {
116 3 2 if (source->type == GIT_REFERENCE_SYMBOLIC)
117 1 3,4 *dest = git_reference__alloc_symbolic(source->name, source->target.symbolic);
118 - else
119 2 5,6 *dest = git_reference__alloc(source->name, &source->target.oid, &source->peel);
120 -
121 3 7,8 GIT_ERROR_CHECK_ALLOC(*dest);
122 -
123 3 9 (*dest)->db = source->db;
124 3 9 GIT_REFCOUNT_INC((*dest)->db);
125 -
126 3 10 return 0;
127 - }
128 -
129 37388 2 void git_reference_free(git_reference *reference)
130 - {
131 37388 2 if (reference == NULL)
132 37410 3,12 return;
133 -
134 26941 4 if (reference->type == GIT_REFERENCE_SYMBOLIC)
135 8844 5 git__free(reference->target.symbolic);
136 -
137 26947 6 if (reference->db)
138 25886 7-10 GIT_REFCOUNT_DEC(reference->db, git_refdb__free);
139 -
140 26958 11 git__free(reference);
141 - }
142 -
143 88 2 int git_reference_delete(git_reference *ref)
144 - {
145 88 2 const git_oid *old_id = NULL;
146 88 2 const char *old_target = NULL;
147 -
148 88 2 if (!strcmp(ref->name, "HEAD")) {
149 2 3 git_error_set(GIT_ERROR_REFERENCE, "cannot delete HEAD");
150 2 4 return GIT_ERROR;
151 - }
152 -
153 86 5 if (ref->type == GIT_REFERENCE_DIRECT)
154 83 6 old_id = &ref->target.oid;
155 - else
156 3 7 old_target = ref->target.symbolic;
157 -
158 86 8 return git_refdb_delete(ref->db, ref->name, old_id, old_target);
159 - }
160 -
161 27 2 int git_reference_remove(git_repository *repo, const char *name)
162 - {
163 - git_refdb *db;
164 - int error;
165 -
166 27 2,3 if ((error = git_repository_refdb__weakptr(&db, repo)) < 0)
167 ##### 4 return error;
168 -
169 27 5 return git_refdb_delete(db, name, NULL, NULL);
170 - }
171 -
172 13011 2 int git_reference_lookup(git_reference **ref_out,
173 - git_repository *repo, const char *name)
174 - {
175 13011 2 return git_reference_lookup_resolved(ref_out, repo, name, 0);
176 - }
177 -
178 5749 2 int git_reference_name_to_id(
179 - git_oid *out, git_repository *repo, const char *name)
180 - {
181 - int error;
182 - git_reference *ref;
183 -
184 5749 2,3 if ((error = git_reference_lookup_resolved(&ref, repo, name, -1)) < 0)
185 2958 4 return error;
186 -
187 2791 5,6 git_oid_cpy(out, git_reference_target(ref));
188 2791 7 git_reference_free(ref);
189 2791 8 return 0;
190 - }
191 -
192 33946 2 static int reference_normalize_for_repo(
193 - git_refname_t out,
194 - git_repository *repo,
195 - const char *name,
196 - bool validate)
197 - {
198 - int precompose;
199 33946 2 unsigned int flags = GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL;
200 -
201 33946 2-4 if (!git_repository__configmap_lookup(&precompose, repo, GIT_CONFIGMAP_PRECOMPOSE) &&
202 - precompose)
203 1025 5 flags |= GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE;
204 -
205 33946 6 if (!validate)
206 1 7 flags |= GIT_REFERENCE_FORMAT__VALIDATION_DISABLE;
207 -
208 33946 8 return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags);
209 - }
210 -
211 31378 2 int git_reference_lookup_resolved(
212 - git_reference **ref_out,
213 - git_repository *repo,
214 - const char *name,
215 - int max_nesting)
216 - {
217 - git_refname_t scan_name;
218 - git_reference_t scan_type;
219 31378 2 int error = 0, nesting;
220 31378 2 git_reference *ref = NULL;
221 - git_refdb *refdb;
222 -
223 31378 2-5 assert(ref_out && repo && name);
224 -
225 31378 6 *ref_out = NULL;
226 -
227 31378 6 if (max_nesting > MAX_NESTING_LEVEL)
228 ##### 7 max_nesting = MAX_NESTING_LEVEL;
229 31378 8 else if (max_nesting < 0)
230 18268 9 max_nesting = DEFAULT_NESTING_LEVEL;
231 -
232 31378 10 scan_type = GIT_REFERENCE_SYMBOLIC;
233 -
234 31378 10,11 if ((error = reference_normalize_for_repo(scan_name, repo, name, true)) < 0)
235 12 12 return error;
236 -
237 31365 13,14 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
238 ##### 15 return error;
239 -
240 52011 16,23 for (nesting = max_nesting;
241 39711 24 nesting >= 0 && scan_type == GIT_REFERENCE_SYMBOLIC;
242 20646 22 nesting--)
243 - {
244 32654 17 if (nesting != max_nesting) {
245 1289 18 strncpy(scan_name, ref->target.symbolic, sizeof(scan_name));
246 1289 18 git_reference_free(ref);
247 - }
248 -
249 32655 19,20 if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0)
250 12009 21 return error;
251 -
252 20646 22 scan_type = ref->type;
253 - }
254 -
255 19357 25,26 if (scan_type != GIT_REFERENCE_DIRECT && max_nesting != 0) {
256 ##### 27 git_error_set(GIT_ERROR_REFERENCE,
257 - "cannot resolve reference (>%u levels deep)", max_nesting);
258 ##### 28 git_reference_free(ref);
259 ##### 29 return -1;
260 - }
261 -
262 19357 30 *ref_out = ref;
263 19357 30 return 0;
264 - }
265 -
266 110 2 int git_reference__read_head(
267 - git_reference **out,
268 - git_repository *repo,
269 - const char *path)
270 - {
271 110 2 git_buf reference = GIT_BUF_INIT;
272 110 2 char *name = NULL;
273 - int error;
274 -
275 110 2,3 if ((error = git_futils_readbuffer(&reference, path)) < 0)
276 2 4 goto out;
277 108 5 git_buf_rtrim(&reference);
278 -
279 108 6 if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) == 0) {
280 106 7 git_buf_consume(&reference, reference.ptr + strlen(GIT_SYMREF));
281 -
282 106 8 name = git_path_basename(path);
283 -
284 106 9,10 if ((*out = git_reference__alloc_symbolic(name, reference.ptr)) == NULL) {
285 ##### 11 error = -1;
286 ##### 11 goto out;
287 - }
288 - } else {
289 2 12,13 if ((error = git_reference_lookup(out, repo, reference.ptr)) < 0)
290 2 14 goto out;
291 - }
292 -
293 - out:
294 110 15 git__free(name);
295 110 16 git_buf_dispose(&reference);
296 -
297 110 17 return error;
298 - }
299 -
300 1689 2 int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname)
301 - {
302 1689 2 int error = 0, i;
303 1689 2 bool fallbackmode = true, foundvalid = false;
304 - git_reference *ref;
305 1689 2 git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT;
306 -
307 - static const char* formatters[] = {
308 - "%s",
309 - GIT_REFS_DIR "%s",
310 - GIT_REFS_TAGS_DIR "%s",
311 - GIT_REFS_HEADS_DIR "%s",
312 - GIT_REFS_REMOTES_DIR "%s",
313 - GIT_REFS_REMOTES_DIR "%s/" GIT_HEAD_FILE,
314 - NULL
315 - };
316 -
317 1689 2 if (*refname)
318 1682 3 git_buf_puts(&name, refname);
319 - else {
320 7 4 git_buf_puts(&name, GIT_HEAD_FILE);
321 7 5 fallbackmode = false;
322 - }
323 -
324 10180 6,22-25 for (i = 0; formatters[i] && (fallbackmode || i == 0); i++) {
325 -
326 8819 7 git_buf_clear(&refnamebuf);
327 -
328 8819 8-10 if ((error = git_buf_printf(&refnamebuf, formatters[i], git_buf_cstr(&name))) < 0)
329 ##### 11 goto cleanup;
330 -
331 8819 12-14 if (!git_reference_is_valid_name(git_buf_cstr(&refnamebuf))) {
332 396 15 error = GIT_EINVALIDSPEC;
333 396 15 continue;
334 - }
335 8423 16 foundvalid = true;
336 -
337 8423 16,17 error = git_reference_lookup_resolved(&ref, repo, git_buf_cstr(&refnamebuf), -1);
338 -
339 8423 18 if (!error) {
340 328 19 *out = ref;
341 328 19 error = 0;
342 328 19 goto cleanup;
343 - }
344 -
345 8095 20 if (error != GIT_ENOTFOUND)
346 ##### 21 goto cleanup;
347 - }
348 -
349 - cleanup:
350 1689 26,27 if (error && !foundvalid) {
351 - /* never found a valid reference name */
352 3 28,29 git_error_set(GIT_ERROR_REFERENCE,
353 - "could not use '%s' as valid reference name", git_buf_cstr(&name));
354 - }
355 -
356 1689 30 if (error == GIT_ENOTFOUND)
357 1358 31 git_error_set(GIT_ERROR_REFERENCE, "no reference found for shorthand '%s'", refname);
358 -
359 1689 32 git_buf_dispose(&name);
360 1689 33 git_buf_dispose(&refnamebuf);
361 1689 34 return error;
362 - }
363 -
364 - /**
365 - * Getters
366 - */
367 12254 2 git_reference_t git_reference_type(const git_reference *ref)
368 - {
369 12254 2,3 assert(ref);
370 12254 4 return ref->type;
371 - }
372 -
373 2089 2 const char *git_reference_name(const git_reference *ref)
374 - {
375 2089 2,3 assert(ref);
376 2089 4 return ref->name;
377 - }
378 -
379 4395 2 git_repository *git_reference_owner(const git_reference *ref)
380 - {
381 4395 2,3 assert(ref);
382 4395 4 return ref->db->repo;
383 - }
384 -
385 6901 2 const git_oid *git_reference_target(const git_reference *ref)
386 - {
387 6901 2,3 assert(ref);
388 -
389 6901 4 if (ref->type != GIT_REFERENCE_DIRECT)
390 2 5 return NULL;
391 -
392 6899 6 return &ref->target.oid;
393 - }
394 -
395 ##### 2 const git_oid *git_reference_target_peel(const git_reference *ref)
396 - {
397 ##### 2,3 assert(ref);
398 -
399 ##### 4-6 if (ref->type != GIT_REFERENCE_DIRECT || git_oid_is_zero(&ref->peel))
400 ##### 7 return NULL;
401 -
402 ##### 8 return &ref->peel;
403 - }
404 -
405 6139 2 const char *git_reference_symbolic_target(const git_reference *ref)
406 - {
407 6139 2,3 assert(ref);
408 -
409 6139 4 if (ref->type != GIT_REFERENCE_SYMBOLIC)
410 ##### 5 return NULL;
411 -
412 6139 6 return ref->target.symbolic;
413 - }
414 -
415 2246 2 static int reference__create(
416 - git_reference **ref_out,
417 - git_repository *repo,
418 - const char *name,
419 - const git_oid *oid,
420 - const char *symbolic,
421 - int force,
422 - const git_signature *signature,
423 - const char *log_message,
424 - const git_oid *old_id,
425 - const char *old_target)
426 - {
427 - git_refname_t normalized;
428 - git_refdb *refdb;
429 2246 2 git_reference *ref = NULL;
430 2246 2 int error = 0;
431 -
432 2246 2-4 assert(repo && name);
433 2246 5-7 assert(symbolic || signature);
434 -
435 2246 8 if (ref_out)
436 2235 9 *ref_out = NULL;
437 -
438 2246 10 error = reference_normalize_for_repo(normalized, repo, name, true);
439 2246 11 if (error < 0)
440 17 12 return error;
441 -
442 2229 13 error = git_repository_refdb__weakptr(&refdb, repo);
443 2229 14 if (error < 0)
444 ##### 15 return error;
445 -
446 2229 16 if (oid != NULL) {
447 1952 17,18 assert(symbolic == NULL);
448 -
449 1952 19,20 if (!git_object__is_valid(repo, oid, GIT_OBJECT_ANY)) {
450 1 21 git_error_set(GIT_ERROR_REFERENCE,
451 - "target OID for the reference doesn't exist on the repository");
452 1 22 return -1;
453 - }
454 -
455 1951 23 ref = git_reference__alloc(normalized, oid, NULL);
456 - } else {
457 - git_refname_t normalized_target;
458 -
459 277 24 error = reference_normalize_for_repo(normalized_target, repo,
460 - symbolic, git_reference__enable_symbolic_ref_target_validation);
461 -
462 277 25 if (error < 0)
463 2 26 return error;
464 -
465 275 27,28 ref = git_reference__alloc_symbolic(normalized, normalized_target);
466 - }
467 -
468 2226 29,30 GIT_ERROR_CHECK_ALLOC(ref);
469 -
470 2226 31,32 if ((error = git_refdb_write(refdb, ref, force, signature, log_message, old_id, old_target)) < 0) {
471 21 33 git_reference_free(ref);
472 21 34 return error;
473 - }
474 -
475 2205 35 if (ref_out == NULL)
476 9 36 git_reference_free(ref);
477 - else
478 2196 37 *ref_out = ref;
479 -
480 2205 38 return 0;
481 - }
482 -
483 2175 2 static int refs_configured_ident(git_signature **out, const git_repository *repo)
484 - {
485 2175 2,3 if (repo->ident_name && repo->ident_email)
486 89 4 return git_signature_now(out, repo->ident_name, repo->ident_email);
487 -
488 - /* if not configured let us fall-through to the next method */
489 2086 5 return -1;
490 - }
491 -
492 2175 2 int git_reference__log_signature(git_signature **out, git_repository *repo)
493 - {
494 - int error;
495 - git_signature *who;
496 -
497 2175 2-5 if(((error = refs_configured_ident(&who, repo)) < 0) &&
498 2086 6,7 ((error = git_signature_default(&who, repo)) < 0) &&
499 - ((error = git_signature_now(&who, "unknown", "unknown")) < 0))
500 ##### 8 return error;
501 -
502 2175 9 *out = who;
503 2175 9 return 0;
504 - }
505 -
506 1645 2 int git_reference_create_matching(
507 - git_reference **ref_out,
508 - git_repository *repo,
509 - const char *name,
510 - const git_oid *id,
511 - int force,
512 - const git_oid *old_id,
513 - const char *log_message)
514 -
515 - {
516 - int error;
517 1645 2 git_signature *who = NULL;
518 -
519 1645 2,3 assert(id);
520 -
521 1645 4,5 if ((error = git_reference__log_signature(&who, repo)) < 0)
522 ##### 6 return error;
523 -
524 1645 7 error = reference__create(
525 - ref_out, repo, name, id, NULL, force, who, log_message, old_id, NULL);
526 -
527 1645 8 git_signature_free(who);
528 1645 9 return error;
529 - }
530 -
531 1632 2 int git_reference_create(
532 - git_reference **ref_out,
533 - git_repository *repo,
534 - const char *name,
535 - const git_oid *id,
536 - int force,
537 - const char *log_message)
538 - {
539 1632 2 return git_reference_create_matching(ref_out, repo, name, id, force, NULL, log_message);
540 - }
541 -
542 285 2 int git_reference_symbolic_create_matching(
543 - git_reference **ref_out,
544 - git_repository *repo,
545 - const char *name,
546 - const char *target,
547 - int force,
548 - const char *old_target,
549 - const char *log_message)
550 - {
551 - int error;
552 285 2 git_signature *who = NULL;
553 -
554 285 2,3 assert(target);
555 -
556 285 4,5 if ((error = git_reference__log_signature(&who, repo)) < 0)
557 ##### 6 return error;
558 -
559 285 7 error = reference__create(
560 - ref_out, repo, name, NULL, target, force, who, log_message, NULL, old_target);
561 -
562 285 8 git_signature_free(who);
563 285 9 return error;
564 - }
565 -
566 274 2 int git_reference_symbolic_create(
567 - git_reference **ref_out,
568 - git_repository *repo,
569 - const char *name,
570 - const char *target,
571 - int force,
572 - const char *log_message)
573 - {
574 274 2 return git_reference_symbolic_create_matching(ref_out, repo, name, target, force, NULL, log_message);
575 - }
576 -
577 36 2 static int ensure_is_an_updatable_direct_reference(git_reference *ref)
578 - {
579 36 2 if (ref->type == GIT_REFERENCE_DIRECT)
580 35 3 return 0;
581 -
582 1 4 git_error_set(GIT_ERROR_REFERENCE, "cannot set OID on symbolic reference");
583 1 5 return -1;
584 - }
585 -
586 5 2 int git_reference_set_target(
587 - git_reference **out,
588 - git_reference *ref,
589 - const git_oid *id,
590 - const char *log_message)
591 - {
592 - int error;
593 - git_repository *repo;
594 -
595 5 2-5 assert(out && ref && id);
596 -
597 5 6 repo = ref->db->repo;
598 -
599 5 6,7 if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0)
600 1 8 return error;
601 -
602 4 9 return git_reference_create_matching(out, repo, ref->name, id, 1, &ref->target.oid, log_message);
603 - }
604 -
605 9 2 static int ensure_is_an_updatable_symbolic_reference(git_reference *ref)
606 - {
607 9 2 if (ref->type == GIT_REFERENCE_SYMBOLIC)
608 8 3 return 0;
609 -
610 1 4 git_error_set(GIT_ERROR_REFERENCE, "cannot set symbolic target on a direct reference");
611 1 5 return -1;
612 - }
613 -
614 9 2 int git_reference_symbolic_set_target(
615 - git_reference **out,
616 - git_reference *ref,
617 - const char *target,
618 - const char *log_message)
619 - {
620 - int error;
621 -
622 9 2-5 assert(out && ref && target);
623 -
624 9 6,7 if ((error = ensure_is_an_updatable_symbolic_reference(ref)) < 0)
625 1 8 return error;
626 -
627 8 9 return git_reference_symbolic_create_matching(
628 8 9 out, ref->db->repo, ref->name, target, 1, ref->target.symbolic, log_message);
629 - }
630 -
631 - typedef struct {
632 - const char *old_name;
633 - git_refname_t new_name;
634 - } rename_cb_data;
635 -
636 40 2 static int update_wt_heads(git_repository *repo, const char *path, void *payload)
637 - {
638 40 2 rename_cb_data *data = (rename_cb_data *) payload;
639 40 2 git_reference *head = NULL;
640 40 2 char *gitdir = NULL;
641 - int error;
642 -
643 40 2,3 if ((error = git_reference__read_head(&head, repo, path)) < 0) {
644 ##### 4 git_error_set(GIT_ERROR_REFERENCE, "could not read HEAD when renaming references");
645 ##### 5 goto out;
646 - }
647 -
648 40 6,7 if ((gitdir = git_path_dirname(path)) == NULL) {
649 ##### 8 error = -1;
650 ##### 8 goto out;
651 - }
652 -
653 40 9-11 if (git_reference_type(head) != GIT_REFERENCE_SYMBOLIC ||
654 40 11 git__strcmp(head->target.symbolic, data->old_name) != 0) {
655 39 12 error = 0;
656 39 12 goto out;
657 - }
658 -
659 - /* Update HEAD it was pointing to the reference being renamed */
660 1 13,14 if ((error = git_repository_create_head(gitdir, data->new_name)) < 0) {
661 ##### 15 git_error_set(GIT_ERROR_REFERENCE, "failed to update HEAD after renaming reference");
662 ##### 16 goto out;
663 - }
664 -
665 - out:
666 40 17 git_reference_free(head);
667 40 18 git__free(gitdir);
668 -
669 40 19 return error;
670 - }
671 -
672 45 2 static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force,
673 - const git_signature *signature, const char *message)
674 - {
675 - git_repository *repo;
676 - git_refname_t normalized;
677 45 2 bool should_head_be_updated = false;
678 45 2 int error = 0;
679 -
680 45 2-5 assert(ref && new_name && signature);
681 -
682 45 6 repo = git_reference_owner(ref);
683 -
684 45 7,8 if ((error = reference_normalize_for_repo(
685 - normalized, repo, new_name, true)) < 0)
686 3 9 return error;
687 -
688 - /* Check if we have to update HEAD. */
689 42 10,11 if ((error = git_branch_is_head(ref)) < 0)
690 ##### 12 return error;
691 -
692 42 13 should_head_be_updated = (error > 0);
693 -
694 42 13,14 if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0)
695 5 15 return error;
696 -
697 - /* Update HEAD if it was pointing to the reference being renamed */
698 37 16 if (should_head_be_updated) {
699 6 17 error = git_repository_set_head(ref->db->repo, normalized);
700 - } else {
701 - rename_cb_data payload;
702 31 18 payload.old_name = ref->name;
703 31 18 memcpy(&payload.new_name, &normalized, sizeof(normalized));
704 -
705 31 18,19 error = git_repository_foreach_head(repo, update_wt_heads, 0, &payload);
706 - }
707 -
708 37 20 return error;
709 - }
710 -
711 -
712 45 2 int git_reference_rename(
713 - git_reference **out,
714 - git_reference *ref,
715 - const char *new_name,
716 - int force,
717 - const char *log_message)
718 - {
719 - git_signature *who;
720 - int error;
721 -
722 45 2-4 assert(out && ref);
723 -
724 45 5,6 if ((error = git_reference__log_signature(&who, ref->db->repo)) < 0)
725 ##### 7 return error;
726 -
727 45 8 error = reference__rename(out, ref, new_name, force, who, log_message);
728 45 9 git_signature_free(who);
729 -
730 45 10 return error;
731 - }
732 -
733 2051 2 int git_reference_resolve(git_reference **ref_out, const git_reference *ref)
734 - {
735 2051 2,3 switch (git_reference_type(ref)) {
736 - case GIT_REFERENCE_DIRECT:
737 1767 4 return git_reference_lookup(ref_out, ref->db->repo, ref->name);
738 -
739 - case GIT_REFERENCE_SYMBOLIC:
740 284 5 return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1);
741 -
742 - default:
743 ##### 6 git_error_set(GIT_ERROR_REFERENCE, "invalid reference");
744 ##### 7 return -1;
745 - }
746 - }
747 -
748 40 2 int git_reference_foreach(
749 - git_repository *repo,
750 - git_reference_foreach_cb callback,
751 - void *payload)
752 - {
753 - git_reference_iterator *iter;
754 - git_reference *ref;
755 - int error;
756 -
757 40 2,3 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
758 ##### 4 return error;
759 -
760 115 5,10,11 while (!(error = git_reference_next(&ref, iter))) {
761 76 6,7 if ((error = callback(ref, payload)) != 0) {
762 1 8 git_error_set_after_callback(error);
763 1 9 break;
764 - }
765 - }
766 -
767 40 12 if (error == GIT_ITEROVER)
768 39 13 error = 0;
769 -
770 40 14 git_reference_iterator_free(iter);
771 40 15 return error;
772 - }
773 -
774 341 2 int git_reference_foreach_name(
775 - git_repository *repo,
776 - git_reference_foreach_name_cb callback,
777 - void *payload)
778 - {
779 - git_reference_iterator *iter;
780 - const char *refname;
781 - int error;
782 -
783 341 2,3 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
784 ##### 4 return error;
785 -
786 4211 5,10,11 while (!(error = git_reference_next_name(&refname, iter))) {
787 3873 6,7 if ((error = callback(refname, payload)) != 0) {
788 3 8 git_error_set_after_callback(error);
789 3 9 break;
790 - }
791 - }
792 -
793 341 12 if (error == GIT_ITEROVER)
794 338 13 error = 0;
795 -
796 341 14 git_reference_iterator_free(iter);
797 341 15 return error;
798 - }
799 -
800 6 2 int git_reference_foreach_glob(
801 - git_repository *repo,
802 - const char *glob,
803 - git_reference_foreach_name_cb callback,
804 - void *payload)
805 - {
806 - git_reference_iterator *iter;
807 - const char *refname;
808 - int error;
809 -
810 6 2,3 if ((error = git_reference_iterator_glob_new(&iter, repo, glob)) < 0)
811 ##### 4 return error;
812 -
813 57 5,10,11 while (!(error = git_reference_next_name(&refname, iter))) {
814 52 6,7 if ((error = callback(refname, payload)) != 0) {
815 1 8 git_error_set_after_callback(error);
816 1 9 break;
817 - }
818 - }
819 -
820 6 12 if (error == GIT_ITEROVER)
821 5 13 error = 0;
822 -
823 6 14 git_reference_iterator_free(iter);
824 6 15 return error;
825 - }
826 -
827 427 2 int git_reference_iterator_new(git_reference_iterator **out, git_repository *repo)
828 - {
829 - git_refdb *refdb;
830 -
831 427 2,3 if (git_repository_refdb__weakptr(&refdb, repo) < 0)
832 ##### 4 return -1;
833 -
834 427 5 return git_refdb_iterator(out, refdb, NULL);
835 - }
836 -
837 61 2 int git_reference_iterator_glob_new(
838 - git_reference_iterator **out, git_repository *repo, const char *glob)
839 - {
840 - git_refdb *refdb;
841 -
842 61 2,3 if (git_repository_refdb__weakptr(&refdb, repo) < 0)
843 ##### 4 return -1;
844 -
845 61 5 return git_refdb_iterator(out, refdb, glob);
846 - }
847 -
848 3097 2 int git_reference_next(git_reference **out, git_reference_iterator *iter)
849 - {
850 3097 2 return git_refdb_iterator_next(out, iter);
851 - }
852 -
853 4400 2 int git_reference_next_name(const char **out, git_reference_iterator *iter)
854 - {
855 4400 2 return git_refdb_iterator_next_name(out, iter);
856 - }
857 -
858 488 2 void git_reference_iterator_free(git_reference_iterator *iter)
859 - {
860 488 2 if (iter == NULL)
861 488 3,5 return;
862 -
863 488 4 git_refdb_iterator_free(iter);
864 - }
865 -
866 2331 2 static int cb__reflist_add(const char *ref, void *data)
867 - {
868 2331 2 char *name = git__strdup(ref);
869 2331 3,4 GIT_ERROR_CHECK_ALLOC(name);
870 2331 5 return git_vector_insert((git_vector *)data, name);
871 - }
872 -
873 136 2 int git_reference_list(
874 - git_strarray *array,
875 - git_repository *repo)
876 - {
877 - git_vector ref_list;
878 -
879 136 2-4 assert(array && repo);
880 -
881 136 5 array->strings = NULL;
882 136 5 array->count = 0;
883 -
884 136 5,6 if (git_vector_init(&ref_list, 8, NULL) < 0)
885 ##### 7 return -1;
886 -
887 136 8,9 if (git_reference_foreach_name(
888 - repo, &cb__reflist_add, (void *)&ref_list) < 0) {
889 ##### 10 git_vector_free(&ref_list);
890 ##### 11 return -1;
891 - }
892 -
893 136 12 array->strings = (char **)git_vector_detach(&array->count, NULL, &ref_list);
894 -
895 136 13 return 0;
896 - }
897 -
898 880764 2 static int is_valid_ref_char(char ch)
899 - {
900 880764 2 if ((unsigned) ch <= ' ')
901 66 3 return 0;
902 -
903 880698 4 switch (ch) {
904 - case '~':
905 - case '^':
906 - case ':':
907 - case '\\':
908 - case '?':
909 - case '[':
910 1107 5 return 0;
911 - default:
912 879591 6 return 1;
913 - }
914 - }
915 -
916 162063 2 static int ensure_segment_validity(const char *name, char may_contain_glob)
917 - {
918 162063 2 const char *current = name;
919 162063 2 char prev = '\0';
920 162063 2 const int lock_len = (int)strlen(GIT_FILELOCK_EXTENSION);
921 - int segment_len;
922 -
923 162063 2 if (*current == '.')
924 13 3 return -1; /* Refname starts with "." */
925 -
926 879555 4,20 for (current = name; ; current++) {
927 1041605 5,6 if (*current == '\0' || *current == '/')
928 - break;
929 -
930 880764 7,8 if (!is_valid_ref_char(*current))
931 1173 9 return -1; /* Illegal character in refname */
932 -
933 879590 10,11 if (prev == '.' && *current == '.')
934 2 12 return -1; /* Refname contains ".." */
935 -
936 879588 13,14 if (prev == '@' && *current == '{')
937 19 15 return -1; /* Refname contains "@{" */
938 -
939 879569 16 if (*current == '*') {
940 1952 17 if (!may_contain_glob)
941 14 18 return -1;
942 1938 19 may_contain_glob = 0;
943 - }
944 -
945 879555 20 prev = *current;
946 879555 20 }
947 -
948 160841 21 segment_len = (int)(current - name);
949 -
950 - /* A refname component can not end with ".lock" */
951 160841 21,22 if (segment_len >= lock_len &&
952 70476 22 !memcmp(current - lock_len, GIT_FILELOCK_EXTENSION, lock_len))
953 6 23 return -1;
954 -
955 160835 24 return segment_len;
956 - }
957 -
958 51183 2 static bool is_all_caps_and_underscore(const char *name, size_t len)
959 - {
960 - size_t i;
961 - char c;
962 -
963 51183 2-4 assert(name && len > 0);
964 -
965 89857 5,10,11 for (i = 0; i < len; i++)
966 - {
967 80246 6 c = name[i];
968 80246 6-8 if ((c < 'A' || c > 'Z') && c != '_')
969 41572 9 return false;
970 - }
971 -
972 9611 12,13 if (*name == '_' || name[len - 1] == '_')
973 2 14 return false;
974 -
975 9609 15 return true;
976 - }
977 -
978 - /* Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 */
979 52523 2 int git_reference__normalize_name(
980 - git_buf *buf,
981 - const char *name,
982 - unsigned int flags)
983 - {
984 - const char *current;
985 52523 2 int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
986 - unsigned int process_flags;
987 52523 2 bool normalize = (buf != NULL);
988 52523 2 bool validate = (flags & GIT_REFERENCE_FORMAT__VALIDATION_DISABLE) == 0;
989 -
990 - #ifdef GIT_USE_ICONV
991 - git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
992 - #endif
993 -
994 52523 2,3 assert(name);
995 -
996 52523 4 process_flags = flags;
997 52523 4 current = (char *)name;
998 -
999 52523 4,5 if (validate && *current == '/')
1000 10 6 goto cleanup;
1001 -
1002 52513 7 if (normalize)
1003 34129 8 git_buf_clear(buf);
1004 -
1005 - #ifdef GIT_USE_ICONV
1006 - if ((flags & GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE) != 0) {
1007 - size_t namelen = strlen(current);
1008 - if ((error = git_path_iconv_init_precompose(&ic)) < 0 ||
1009 - (error = git_path_iconv(&ic, &current, &namelen)) < 0)
1010 - goto cleanup;
1011 - error = GIT_EINVALIDSPEC;
1012 - }
1013 - #endif
1014 -
1015 52513 9 if (!validate) {
1016 1 10 git_buf_sets(buf, current);
1017 -
1018 1 11-14 error = git_buf_oom(buf) ? -1 : 0;
1019 1 15 goto cleanup;
1020 - }
1021 -
1022 - while (true) {
1023 162064 16 char may_contain_glob = process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
1024 -
1025 162064 16 segment_len = ensure_segment_validity(current, may_contain_glob);
1026 162066 17 if (segment_len < 0)
1027 1227 18 goto cleanup;
1028 -
1029 160839 19 if (segment_len > 0) {
1030 - /*
1031 - * There may only be one glob in a pattern, thus we reset
1032 - * the pattern-flag in case the current segment has one.
1033 - */
1034 160795 20 if (memchr(current, '*', segment_len))
1035 1936 21 process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
1036 -
1037 160795 22 if (normalize) {
1038 96875 23 size_t cur_len = git_buf_len(buf);
1039 -
1040 96875 24,25 git_buf_joinpath(buf, git_buf_cstr(buf), current);
1041 96876 26-29 git_buf_truncate(buf,
1042 96876 26 cur_len + segment_len + (segments_count ? 1 : 0));
1043 -
1044 96873 30,31 if (git_buf_oom(buf)) {
1045 ##### 32 error = -1;
1046 ##### 32 goto cleanup;
1047 - }
1048 - }
1049 -
1050 160793 33 segments_count++;
1051 - }
1052 -
1053 - /* No empty segment is allowed when not normalizing */
1054 160837 34,35 if (segment_len == 0 && !normalize)
1055 12 36 goto cleanup;
1056 -
1057 160825 37 if (current[segment_len] == '\0')
1058 51273 38 break;
1059 -
1060 109552 39 current += segment_len + 1;
1061 109552 39 }
1062 -
1063 - /* A refname can not be empty */
1064 51273 40,41 if (segment_len == 0 && segments_count == 0)
1065 3 42 goto cleanup;
1066 -
1067 - /* A refname can not end with "." */
1068 51270 43 if (current[segment_len - 1] == '.')
1069 4 44 goto cleanup;
1070 -
1071 - /* A refname can not end with "/" */
1072 51266 45 if (current[segment_len - 1] == '/')
1073 3 46 goto cleanup;
1074 -
1075 51263 47,48 if ((segments_count == 1 ) && !(flags & GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL))
1076 4 49 goto cleanup;
1077 -
1078 51259 50,51 if ((segments_count == 1 ) &&
1079 10069 51,53 !(flags & GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND) &&
1080 9993 52,54 !(is_all_caps_and_underscore(name, (size_t)segment_len) ||
1081 386 54,55 ((flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name))))
1082 - goto cleanup;
1083 -
1084 50874 56 if ((segments_count > 1)
1085 41190 57,58 && (is_all_caps_and_underscore(name, strchr(name, '/') - name)))
1086 2 59 goto cleanup;
1087 -
1088 50871 60 error = 0;
1089 -
1090 - cleanup:
1091 52522 61 if (error == GIT_EINVALIDSPEC)
1092 1650 62 git_error_set(
1093 - GIT_ERROR_REFERENCE,
1094 - "the given reference name '%s' is not valid", name);
1095 -
1096 52522 63,64 if (error && normalize)
1097 129 65 git_buf_dispose(buf);
1098 -
1099 - #ifdef GIT_USE_ICONV
1100 - git_path_iconv_clear(&ic);
1101 - #endif
1102 -
1103 52522 66 return error;
1104 - }
1105 -
1106 34098 2 int git_reference_normalize_name(
1107 - char *buffer_out,
1108 - size_t buffer_size,
1109 - const char *name,
1110 - unsigned int flags)
1111 - {
1112 34098 2 git_buf buf = GIT_BUF_INIT;
1113 - int error;
1114 -
1115 34098 2,3 if ((error = git_reference__normalize_name(&buf, name, flags)) < 0)
1116 128 4 goto cleanup;
1117 -
1118 33969 5,6 if (git_buf_len(&buf) > buffer_size - 1) {
1119 1 7 git_error_set(
1120 - GIT_ERROR_REFERENCE,
1121 - "the provided buffer is too short to hold the normalization of '%s'", name);
1122 1 8 error = GIT_EBUFS;
1123 1 8 goto cleanup;
1124 - }
1125 -
1126 33968 9 git_buf_copy_cstr(buffer_out, buffer_size, &buf);
1127 -
1128 33968 10 error = 0;
1129 -
1130 - cleanup:
1131 34097 11 git_buf_dispose(&buf);
1132 34096 12 return error;
1133 - }
1134 -
1135 - #define GIT_REFERENCE_TYPEMASK (GIT_REFERENCE_DIRECT | GIT_REFERENCE_SYMBOLIC)
1136 -
1137 7 2 int git_reference_cmp(
1138 - const git_reference *ref1,
1139 - const git_reference *ref2)
1140 - {
1141 - git_reference_t type1, type2;
1142 7 2-4 assert(ref1 && ref2);
1143 -
1144 7 5 type1 = git_reference_type(ref1);
1145 7 6 type2 = git_reference_type(ref2);
1146 -
1147 - /* let's put symbolic refs before OIDs */
1148 7 7 if (type1 != type2)
1149 1 8-11 return (type1 == GIT_REFERENCE_SYMBOLIC) ? -1 : 1;
1150 -
1151 6 12 if (type1 == GIT_REFERENCE_SYMBOLIC)
1152 1 13 return strcmp(ref1->target.symbolic, ref2->target.symbolic);
1153 -
1154 5 14 return git_oid__cmp(&ref1->target.oid, &ref2->target.oid);
1155 - }
1156 -
1157 - /**
1158 - * Get the end of a chain of references. If the final one is not
1159 - * found, we return the reference just before that.
1160 - */
1161 531 2 static int get_terminal(git_reference **out, git_repository *repo, const char *ref_name, int nesting)
1162 - {
1163 - git_reference *ref;
1164 531 2 int error = 0;
1165 -
1166 531 2 if (nesting > MAX_NESTING_LEVEL) {
1167 ##### 3 git_error_set(GIT_ERROR_REFERENCE, "reference chain too deep (%d)", nesting);
1168 ##### 4 return GIT_ENOTFOUND;
1169 - }
1170 -
1171 - /* set to NULL to let the caller know that they're at the end of the chain */
1172 531 5,6 if ((error = git_reference_lookup(&ref, repo, ref_name)) < 0) {
1173 64 7 *out = NULL;
1174 64 7 return error;
1175 - }
1176 -
1177 467 8,9 if (git_reference_type(ref) == GIT_REFERENCE_DIRECT) {
1178 221 10 *out = ref;
1179 221 10 error = 0;
1180 - } else {
1181 246 11,12 error = get_terminal(out, repo, git_reference_symbolic_target(ref), nesting + 1);
1182 246 13,14 if (error == GIT_ENOTFOUND && !*out)
1183 62 15 *out = ref;
1184 - else
1185 184 16 git_reference_free(ref);
1186 - }
1187 -
1188 467 17 return error;
1189 - }
1190 -
1191 - /*
1192 - * Starting with the reference given by `ref_name`, follows symbolic
1193 - * references until a direct reference is found and updated the OID
1194 - * on that direct reference to `oid`.
1195 - */
1196 285 2 int git_reference__update_terminal(
1197 - git_repository *repo,
1198 - const char *ref_name,
1199 - const git_oid *oid,
1200 - const git_signature *sig,
1201 - const char *log_message)
1202 - {
1203 285 2 git_reference *ref = NULL, *ref2 = NULL;
1204 285 2 git_signature *who = NULL;
1205 - const git_signature *to_use;
1206 285 2 int error = 0;
1207 -
1208 285 2-4 if (!sig && (error = git_reference__log_signature(&who, repo)) < 0)
1209 ##### 5 return error;
1210 -
1211 285 6-8 to_use = sig ? sig : who;
1212 285 9 error = get_terminal(&ref, repo, ref_name, 0);
1213 -
1214 - /* found a dangling symref */
1215 285 10,11 if (error == GIT_ENOTFOUND && ref) {
1216 62 12-14 assert(git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC);
1217 62 15 git_error_clear();
1218 62 16 error = reference__create(&ref2, repo, ref->target.symbolic, oid, NULL, 0, to_use,
1219 - log_message, NULL, NULL);
1220 223 17 } else if (error == GIT_ENOTFOUND) {
1221 2 18 git_error_clear();
1222 2 19 error = reference__create(&ref2, repo, ref_name, oid, NULL, 0, to_use,
1223 - log_message, NULL, NULL);
1224 221 20 } else if (error == 0) {
1225 221 21-23 assert(git_reference_type(ref) == GIT_REFERENCE_DIRECT);
1226 221 24 error = reference__create(&ref2, repo, ref->name, oid, NULL, 1, to_use,
1227 221 24 log_message, &ref->target.oid, NULL);
1228 - }
1229 -
1230 285 25 git_reference_free(ref2);
1231 285 26 git_reference_free(ref);
1232 285 27 git_signature_free(who);
1233 285 28 return error;
1234 - }
1235 -
1236 126 2 static const char *commit_type(const git_commit *commit)
1237 - {
1238 126 2 unsigned int count = git_commit_parentcount(commit);
1239 -
1240 126 3 if (count >= 2)
1241 1 4 return " (merge)";
1242 125 5 else if (count == 0)
1243 63 6 return " (initial)";
1244 - else
1245 62 7 return "";
1246 - }
1247 -
1248 126 2 int git_reference__update_for_commit(
1249 - git_repository *repo,
1250 - git_reference *ref,
1251 - const char *ref_name,
1252 - const git_oid *id,
1253 - const char *operation)
1254 - {
1255 126 2 git_reference *ref_new = NULL;
1256 126 2 git_commit *commit = NULL;
1257 126 2 git_buf reflog_msg = GIT_BUF_INIT;
1258 - const git_signature *who;
1259 - int error;
1260 -
1261 126 2,3,9,10 if ((error = git_commit_lookup(&commit, repo, id)) < 0 ||
1262 126 4-8 (error = git_buf_printf(&reflog_msg, "%s%s: %s",
1263 - operation ? operation : "commit",
1264 - commit_type(commit),
1265 - git_commit_summary(commit))) < 0)
1266 - goto done;
1267 -
1268 126 11 who = git_commit_committer(commit);
1269 -
1270 126 12 if (ref) {
1271 31 13,14 if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0)
1272 ##### 15 return error;
1273 -
1274 31 16,17 error = reference__create(&ref_new, repo, ref->name, id, NULL, 1, who,
1275 31 16 git_buf_cstr(&reflog_msg), &ref->target.oid, NULL);
1276 - }
1277 - else
1278 95 18,19 error = git_reference__update_terminal(
1279 - repo, ref_name, id, who, git_buf_cstr(&reflog_msg));
1280 -
1281 - done:
1282 126 20 git_reference_free(ref_new);
1283 126 21 git_buf_dispose(&reflog_msg);
1284 126 22 git_commit_free(commit);
1285 126 23 return error;
1286 - }
1287 -
1288 8 2 int git_reference_has_log(git_repository *repo, const char *refname)
1289 - {
1290 - int error;
1291 - git_refdb *refdb;
1292 -
1293 8 2-4 assert(repo && refname);
1294 -
1295 8 5,6 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
1296 ##### 7 return error;
1297 -
1298 8 8 return git_refdb_has_log(refdb, refname);
1299 - }
1300 -
1301 61 2 int git_reference_ensure_log(git_repository *repo, const char *refname)
1302 - {
1303 - int error;
1304 - git_refdb *refdb;
1305 -
1306 61 2-4 assert(repo && refname);
1307 -
1308 61 5,6 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
1309 ##### 7 return error;
1310 -
1311 61 8 return git_refdb_ensure_log(refdb, refname);
1312 - }
1313 -
1314 731 2 int git_reference__is_branch(const char *ref_name)
1315 - {
1316 731 2 return git__prefixcmp(ref_name, GIT_REFS_HEADS_DIR) == 0;
1317 - }
1318 -
1319 394 2 int git_reference_is_branch(const git_reference *ref)
1320 - {
1321 394 2,3 assert(ref);
1322 394 4 return git_reference__is_branch(ref->name);
1323 - }
1324 -
1325 82 2 int git_reference__is_remote(const char *ref_name)
1326 - {
1327 82 2 return git__prefixcmp(ref_name, GIT_REFS_REMOTES_DIR) == 0;
1328 - }
1329 -
1330 7 2 int git_reference_is_remote(const git_reference *ref)
1331 - {
1332 7 2,3 assert(ref);
1333 7 4 return git_reference__is_remote(ref->name);
1334 - }
1335 -
1336 73 2 int git_reference__is_tag(const char *ref_name)
1337 - {
1338 73 2 return git__prefixcmp(ref_name, GIT_REFS_TAGS_DIR) == 0;
1339 - }
1340 -
1341 11 2 int git_reference_is_tag(const git_reference *ref)
1342 - {
1343 11 2,3 assert(ref);
1344 11 4 return git_reference__is_tag(ref->name);
1345 - }
1346 -
1347 3 2 int git_reference__is_note(const char *ref_name)
1348 - {
1349 3 2 return git__prefixcmp(ref_name, GIT_REFS_NOTES_DIR) == 0;
1350 - }
1351 -
1352 3 2 int git_reference_is_note(const git_reference *ref)
1353 - {
1354 3 2,3 assert(ref);
1355 3 4 return git_reference__is_note(ref->name);
1356 - }
1357 -
1358 ##### 2 static int peel_error(int error, const git_reference *ref, const char* msg)
1359 - {
1360 ##### 2,3 git_error_set(
1361 - GIT_ERROR_INVALID,
1362 - "the reference '%s' cannot be peeled - %s", git_reference_name(ref), msg);
1363 ##### 4 return error;
1364 - }
1365 -
1366 4105 2 int git_reference_peel(
1367 - git_object **peeled,
1368 - const git_reference *ref,
1369 - git_object_t target_type)
1370 - {
1371 4105 2 const git_reference *resolved = NULL;
1372 4105 2 git_reference *allocated = NULL;
1373 4105 2 git_object *target = NULL;
1374 - int error;
1375 -
1376 4105 2,3 assert(ref);
1377 -
1378 4105 4 if (ref->type == GIT_REFERENCE_DIRECT) {
1379 3969 5 resolved = ref;
1380 - } else {
1381 136 6,7 if ((error = git_reference_resolve(&allocated, ref)) < 0)
1382 ##### 8 return peel_error(error, ref, "Cannot resolve reference");
1383 -
1384 136 9 resolved = allocated;
1385 - }
1386 -
1387 - /*
1388 - * If we try to peel an object to a tag, we cannot use
1389 - * the fully peeled object, as that will always resolve
1390 - * to a commit. So we only want to use the peeled value
1391 - * if it is not zero and the target is not a tag.
1392 - */
1393 4105 10-12 if (target_type != GIT_OBJECT_TAG && !git_oid_is_zero(&resolved->peel)) {
1394 2 13,14 error = git_object_lookup(&target,
1395 - git_reference_owner(ref), &resolved->peel, GIT_OBJECT_ANY);
1396 - } else {
1397 4103 15,16 error = git_object_lookup(&target,
1398 - git_reference_owner(ref), &resolved->target.oid, GIT_OBJECT_ANY);
1399 - }
1400 -
1401 4105 17 if (error < 0) {
1402 ##### 18 peel_error(error, ref, "Cannot retrieve reference target");
1403 ##### 19 goto cleanup;
1404 - }
1405 -
1406 4105 20-22 if (target_type == GIT_OBJECT_ANY && git_object_type(target) != GIT_OBJECT_TAG)
1407 56 23 error = git_object_dup(peeled, target);
1408 - else
1409 4049 24 error = git_object_peel(peeled, target, target_type);
1410 -
1411 - cleanup:
1412 4105 25 git_object_free(target);
1413 4105 26 git_reference_free(allocated);
1414 -
1415 4105 27 return error;
1416 - }
1417 -
1418 18387 2 int git_reference__is_valid_name(const char *refname, unsigned int flags)
1419 - {
1420 18387 2,3 if (git_reference__normalize_name(NULL, refname, flags) < 0) {
1421 1521 4 git_error_clear();
1422 1521 5 return false;
1423 - }
1424 -
1425 16866 6 return true;
1426 - }
1427 -
1428 14532 2 int git_reference_is_valid_name(const char *refname)
1429 - {
1430 14532 2 return git_reference__is_valid_name(refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL);
1431 - }
1432 -
1433 270 2 const char *git_reference__shorthand(const char *name)
1434 - {
1435 270 2,3 if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR))
1436 241 4 return name + strlen(GIT_REFS_HEADS_DIR);
1437 29 5,6 else if (!git__prefixcmp(name, GIT_REFS_TAGS_DIR))
1438 7 7 return name + strlen(GIT_REFS_TAGS_DIR);
1439 22 8,9 else if (!git__prefixcmp(name, GIT_REFS_REMOTES_DIR))
1440 21 10 return name + strlen(GIT_REFS_REMOTES_DIR);
1441 1 11,12 else if (!git__prefixcmp(name, GIT_REFS_DIR))
1442 1 13 return name + strlen(GIT_REFS_DIR);
1443 -
1444 - /* No shorthands are avaiable, so just return the name */
1445 ##### 14 return name;
1446 - }
1447 -
1448 26 2 const char *git_reference_shorthand(const git_reference *ref)
1449 - {
1450 26 2 return git_reference__shorthand(ref->name);
1451 - }
1452 -
1453 18 2 int git_reference__is_unborn_head(bool *unborn, const git_reference *ref, git_repository *repo)
1454 - {
1455 - int error;
1456 - git_reference *tmp_ref;
1457 18 2-5 assert(unborn && ref && repo);
1458 -
1459 18 6 if (ref->type == GIT_REFERENCE_DIRECT) {
1460 4 7 *unborn = 0;
1461 4 7 return 0;
1462 - }
1463 -
1464 14 8 error = git_reference_lookup_resolved(&tmp_ref, repo, ref->name, -1);
1465 14 9 git_reference_free(tmp_ref);
1466 -
1467 14 10,11 if (error != 0 && error != GIT_ENOTFOUND)
1468 ##### 12 return error;
1469 14 13,14 else if (error == GIT_ENOTFOUND && git__strcmp(ref->name, GIT_HEAD_FILE) == 0)
1470 2 15 *unborn = true;
1471 - else
1472 12 16 *unborn = false;
1473 -
1474 14 17 return 0;
1475 - }