Bug Summary

File:got/../lib/reference.c
Warning:line 513, column 6
Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'ref')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd6.9 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name reference.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/local/lib/clang/11.1.0 -I /home/ben/Projects/got/got/../include -I /home/ben/Projects/got/got/../lib -D GOT_LIBEXECDIR=/home/ben/bin -D GOT_VERSION=0.53-current -internal-isystem /usr/local/lib/clang/11.1.0/include -internal-externc-isystem /usr/include -O0 -fdebug-compilation-dir /home/ben/Projects/got/got/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/got/scan/2021-05-28-230913-68537-1 -x c /home/ben/Projects/got/got/../lib/reference.c
1/*
2 * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <sys/types.h>
18#include <sys/queue.h>
19#include <sys/stat.h>
20
21#include <errno(*__errno()).h>
22#include <ctype.h>
23#include <dirent.h>
24#include <limits.h>
25#include <sha1.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30#include <util.h>
31#include <zlib.h>
32#include <time.h>
33#include <libgen.h>
34
35#include "got_error.h"
36#include "got_object.h"
37#include "got_repository.h"
38#include "got_reference.h"
39#include "got_opentemp.h"
40#include "got_path.h"
41
42#include "got_lib_sha1.h"
43#include "got_lib_delta.h"
44#include "got_lib_inflate.h"
45#include "got_lib_object.h"
46#include "got_lib_object_idset.h"
47#include "got_lib_lockfile.h"
48
49#ifndef nitems
50#define nitems(_a)(sizeof(_a) / sizeof((_a)[0])) (sizeof(_a) / sizeof((_a)[0]))
51#endif
52
53#define GOT_REF_HEADS"heads" "heads"
54#define GOT_REF_TAGS"tags" "tags"
55#define GOT_REF_REMOTES"remotes" "remotes"
56
57/*
58 * We do not resolve tags yet, and don't yet care about sorting refs either,
59 * so packed-refs files we write contain a minimal header which disables all
60 * packed-refs "traits" supported by Git.
61 */
62#define GOT_PACKED_REFS_HEADER"# pack-refs with:" "# pack-refs with:"
63
64/* A symbolic reference. */
65struct got_symref {
66 char *name;
67 char *ref;
68};
69
70#define GOT_REF_RECURSE_MAX20 20
71
72/* A non-symbolic reference (there is no better designation). */
73struct got_ref {
74 char *name;
75 u_int8_t sha1[SHA1_DIGEST_LENGTH20];
76};
77
78/* A reference which points to an arbitrary object. */
79struct got_reference {
80 unsigned int flags;
81#define GOT_REF_IS_SYMBOLIC0x01 0x01
82#define GOT_REF_IS_PACKED0x02 0x02
83
84 union {
85 struct got_ref ref;
86 struct got_symref symref;
87 } ref;
88
89 struct got_lockfile *lf;
90};
91
92static const struct got_error *
93alloc_ref(struct got_reference **ref, const char *name,
94 struct got_object_id *id, int flags)
95{
96 const struct got_error *err = NULL((void *)0);
97
98 *ref = calloc(1, sizeof(**ref));
99 if (*ref == NULL((void *)0))
100 return got_error_from_errno("calloc");
101
102 memcpy((*ref)->ref.ref.sha1, id->sha1, sizeof((*ref)->ref.ref.sha1));
103 (*ref)->flags = flags;
104 (*ref)->ref.ref.name = strdup(name);
105 if ((*ref)->ref.ref.name == NULL((void *)0)) {
106 err = got_error_from_errno("strdup");
107 got_ref_close(*ref);
108 *ref = NULL((void *)0);
109 }
110 return err;
111}
112
113static const struct got_error *
114alloc_symref(struct got_reference **ref, const char *name,
115 const char *target_ref, int flags)
116{
117 const struct got_error *err = NULL((void *)0);
118
119 *ref = calloc(1, sizeof(**ref));
120 if (*ref == NULL((void *)0))
121 return got_error_from_errno("calloc");
122
123 (*ref)->flags = GOT_REF_IS_SYMBOLIC0x01 | flags;
124 (*ref)->ref.symref.name = strdup(name);
125 if ((*ref)->ref.symref.name == NULL((void *)0)) {
126 err = got_error_from_errno("strdup");
127 got_ref_close(*ref);
128 *ref = NULL((void *)0);
129 return err;
130 }
131 (*ref)->ref.symref.ref = strdup(target_ref);
132 if ((*ref)->ref.symref.ref == NULL((void *)0)) {
133 err = got_error_from_errno("strdup");
134 got_ref_close(*ref);
135 *ref = NULL((void *)0);
136 }
137 return err;
138}
139
140static const struct got_error *
141parse_symref(struct got_reference **ref, const char *name, const char *line)
142{
143 if (line[0] == '\0')
144 return got_error(GOT_ERR_BAD_REF_DATA57);
145
146 return alloc_symref(ref, name, line, 0);
147}
148
149static const struct got_error *
150parse_ref_line(struct got_reference **ref, const char *name, const char *line)
151{
152 struct got_object_id id;
153
154 if (strncmp(line, "ref: ", 5) == 0) {
155 line += 5;
156 return parse_symref(ref, name, line);
157 }
158
159 if (!got_parse_sha1_digest(id.sha1, line))
160 return got_error(GOT_ERR_BAD_REF_DATA57);
161
162 return alloc_ref(ref, name, &id, 0);
163}
164
165static const struct got_error *
166parse_ref_file(struct got_reference **ref, const char *name,
167 const char *absname, const char *abspath, int lock)
168{
169 const struct got_error *err = NULL((void *)0);
170 FILE *f;
171 char *line = NULL((void *)0);
172 size_t linesize = 0;
173 ssize_t linelen;
174 struct got_lockfile *lf = NULL((void *)0);
175
176 if (lock) {
177 err = got_lockfile_lock(&lf, abspath);
178 if (err) {
179 if (err->code == GOT_ERR_ERRNO1 && errno(*__errno()) == ENOENT2)
180 err = got_error_not_ref(name);
181 return err;
182 }
183 }
184
185 f = fopen(abspath, "rb");
186 if (f == NULL((void *)0)) {
187 if (errno(*__errno()) != ENOTDIR20 && errno(*__errno()) != ENOENT2)
188 err = got_error_from_errno2("fopen", abspath);
189 else
190 err = got_error_not_ref(name);
191 if (lock)
192 got_lockfile_unlock(lf);
193 return err;
194 }
195
196 linelen = getline(&line, &linesize, f);
197 if (linelen == -1) {
198 if (feof(f)(!__isthreaded ? (((f)->_flags & 0x0020) != 0) : (feof
)(f))
)
199 err = NULL((void *)0); /* ignore empty files (could be locks) */
200 else {
201 if (errno(*__errno()) == EISDIR21)
202 err = got_error(GOT_ERR_NOT_REF5);
203 else if (ferror(f)(!__isthreaded ? (((f)->_flags & 0x0040) != 0) : (ferror
)(f))
)
204 err = got_ferror(f, GOT_ERR_IO6);
205 else
206 err = got_error_from_errno2("getline", abspath);
207 }
208 if (lock)
209 got_lockfile_unlock(lf);
210 goto done;
211 }
212 while (linelen > 0 && line[linelen - 1] == '\n') {
213 line[linelen - 1] = '\0';
214 linelen--;
215 }
216
217 err = parse_ref_line(ref, absname, line);
218 if (lock) {
219 if (err)
220 got_lockfile_unlock(lf);
221 else {
222 if (*ref)
223 (*ref)->lf = lf;
224 else
225 got_lockfile_unlock(lf);
226 }
227 }
228done:
229 free(line);
230 if (fclose(f) == EOF(-1) && err == NULL((void *)0)) {
231 err = got_error_from_errno("fclose");
232 if (*ref) {
233 if (lock)
234 got_ref_unlock(*ref);
235 got_ref_close(*ref);
236 *ref = NULL((void *)0);
237 }
238 }
239 return err;
240}
241
242static int
243is_well_known_ref(const char *refname)
244{
245 return (strcmp(refname, GOT_REF_HEAD"HEAD") == 0 ||
246 strcmp(refname, GOT_REF_ORIG_HEAD"ORIG_HEAD") == 0 ||
247 strcmp(refname, GOT_REF_MERGE_HEAD"MERGE_HEAD") == 0 ||
248 strcmp(refname, GOT_REF_FETCH_HEAD"FETCH_HEAD") == 0);
249}
250
251static char *
252get_refs_dir_path(struct got_repository *repo, const char *refname)
253{
254 if (is_well_known_ref(refname) || strncmp(refname, "refs/", 5) == 0)
255 return strdup(got_repo_get_path_git_dir(repo));
256
257 return got_repo_get_path_refs(repo);
258}
259
260static int
261is_valid_ref_name(const char *name)
262{
263 const char *s, *seg;
264 const char forbidden[] = { ' ', '~', '^', ':', '?', '*', '[' , '\\' };
265 const char *forbidden_seq[] = { "//", "..", "@{" };
266 const char *lfs = GOT_LOCKFILE_SUFFIX".lock";
267 const size_t lfs_len = sizeof(GOT_LOCKFILE_SUFFIX".lock") - 1;
268 size_t i;
269
270 if (name[0] == '@' && name[1] == '\0')
271 return 0;
272
273 s = name;
274 seg = s;
275 if (seg[0] == '\0' || seg[0] == '.' || seg[0] == '/')
276 return 0;
277 while (*s) {
278 for (i = 0; i < nitems(forbidden)(sizeof(forbidden) / sizeof((forbidden)[0])); i++) {
279 if (*s == forbidden[i])
280 return 0;
281 }
282 for (i = 0; i < nitems(forbidden_seq)(sizeof(forbidden_seq) / sizeof((forbidden_seq)[0])); i++) {
283 if (s[0] == forbidden_seq[i][0] &&
284 s[1] == forbidden_seq[i][1])
285 return 0;
286 }
287 if (iscntrl((unsigned char)s[0]))
288 return 0;
289 if (s[0] == '.' && s[1] == '\0')
290 return 0;
291 if (*s == '/') {
292 const char *nextseg = s + 1;
293 if (nextseg[0] == '\0' || nextseg[0] == '.' ||
294 nextseg[0] == '/')
295 return 0;
296 if (seg <= s - lfs_len &&
297 strncmp(s - lfs_len, lfs, lfs_len) == 0)
298 return 0;
299 seg = nextseg;
300 }
301 s++;
302 }
303
304 if (seg <= s - lfs_len &&
305 strncmp(s - lfs_len, lfs, lfs_len) == 0)
306 return 0;
307
308 return 1;
309}
310
311const struct got_error *
312got_ref_alloc(struct got_reference **ref, const char *name,
313 struct got_object_id *id)
314{
315 if (!is_valid_ref_name(name))
316 return got_error_path(name, GOT_ERR_BAD_REF_NAME65);
317
318 return alloc_ref(ref, name, id, 0);
319}
320
321const struct got_error *
322got_ref_alloc_symref(struct got_reference **ref, const char *name,
323 struct got_reference *target_ref)
324{
325 if (!is_valid_ref_name(name))
326 return got_error_path(name, GOT_ERR_BAD_REF_NAME65);
327
328 return alloc_symref(ref, name, got_ref_get_name(target_ref), 0);
329}
330
331static const struct got_error *
332parse_packed_ref_line(struct got_reference **ref, const char *abs_refname,
333 const char *line)
334{
335 struct got_object_id id;
336 const char *name;
337
338 *ref = NULL((void *)0);
339
340 if (line[0] == '#' || line[0] == '^')
341 return NULL((void *)0);
342
343 if (!got_parse_sha1_digest(id.sha1, line))
344 return got_error(GOT_ERR_BAD_REF_DATA57);
345
346 if (abs_refname) {
347 if (strcmp(line + SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1), abs_refname) != 0)
348 return NULL((void *)0);
349 name = abs_refname;
350 } else
351 name = line + SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1);
352
353 return alloc_ref(ref, name, &id, GOT_REF_IS_PACKED0x02);
354}
355
356static const struct got_error *
357open_packed_ref(struct got_reference **ref, FILE *f, const char **subdirs,
358 int nsubdirs, const char *refname)
359{
360 const struct got_error *err = NULL((void *)0);
361 char *abs_refname;
362 char *line = NULL((void *)0);
363 size_t linesize = 0;
364 ssize_t linelen;
365 int i, ref_is_absolute = (strncmp(refname, "refs/", 5) == 0);
366
367 *ref = NULL((void *)0);
368
369 if (ref_is_absolute)
370 abs_refname = (char *)refname;
371 do {
372 linelen = getline(&line, &linesize, f);
373 if (linelen == -1) {
374 if (feof(f)(!__isthreaded ? (((f)->_flags & 0x0020) != 0) : (feof
)(f))
)
375 break;
376 err = got_ferror(f, GOT_ERR_BAD_REF_DATA57);
377 break;
378 }
379 if (linelen > 0 && line[linelen - 1] == '\n')
380 line[linelen - 1] = '\0';
381 for (i = 0; i < nsubdirs; i++) {
382 if (!ref_is_absolute &&
383 asprintf(&abs_refname, "refs/%s/%s", subdirs[i],
384 refname) == -1)
385 return got_error_from_errno("asprintf");
386 err = parse_packed_ref_line(ref, abs_refname, line);
387 if (!ref_is_absolute)
388 free(abs_refname);
389 if (err || *ref != NULL((void *)0))
390 break;
391 }
392 if (err)
393 break;
394 } while (*ref == NULL((void *)0));
395 free(line);
396
397 return err;
398}
399
400static const struct got_error *
401open_ref(struct got_reference **ref, const char *path_refs, const char *subdir,
402 const char *name, int lock)
403{
404 const struct got_error *err = NULL((void *)0);
405 char *path = NULL((void *)0);
406 char *absname = NULL((void *)0);
407 int ref_is_absolute = (strncmp(name, "refs/", 5) == 0);
408 int ref_is_well_known = (subdir[0] == '\0' && is_well_known_ref(name));
409
410 *ref = NULL((void *)0);
411
412 if (!is_valid_ref_name(name))
413 return got_error_path(name, GOT_ERR_BAD_REF_NAME65);
414
415 if (ref_is_absolute || ref_is_well_known) {
416 if (asprintf(&path, "%s/%s", path_refs, name) == -1)
417 return got_error_from_errno("asprintf");
418 absname = (char *)name;
419 } else {
420 if (asprintf(&path, "%s/%s%s%s", path_refs, subdir,
421 subdir[0] ? "/" : "", name) == -1)
422 return got_error_from_errno("asprintf");
423
424 if (asprintf(&absname, "refs/%s%s%s",
425 subdir, subdir[0] ? "/" : "", name) == -1) {
426 err = got_error_from_errno("asprintf");
427 goto done;
428 }
429 }
430
431 err = parse_ref_file(ref, name, absname, path, lock);
432done:
433 if (!ref_is_absolute && !ref_is_well_known)
434 free(absname);
435 free(path);
436 return err;
437}
438
439const struct got_error *
440got_ref_open(struct got_reference **ref, struct got_repository *repo,
441 const char *refname, int lock)
442{
443 const struct got_error *err = NULL((void *)0);
444 char *path_refs = NULL((void *)0);
445 const char *subdirs[] = {
446 GOT_REF_HEADS"heads", GOT_REF_TAGS"tags", GOT_REF_REMOTES"remotes"
447 };
448 size_t i;
449 int well_known = is_well_known_ref(refname);
450 struct got_lockfile *lf = NULL((void *)0);
451
452 *ref = NULL((void *)0);
453
454 path_refs = get_refs_dir_path(repo, refname);
455 if (path_refs == NULL((void *)0)) {
34
Assuming 'path_refs' is not equal to NULL
35
Taking false branch
456 err = got_error_from_errno2("get_refs_dir_path", refname);
457 goto done;
458 }
459
460 if (well_known
35.1
'well_known' is 0
) {
36
Taking false branch
461 err = open_ref(ref, path_refs, "", refname, lock);
462 } else {
463 char *packed_refs_path;
464 FILE *f;
465
466 /* Search on-disk refs before packed refs! */
467 for (i = 0; i < nitems(subdirs)(sizeof(subdirs) / sizeof((subdirs)[0])); i++) {
37
Loop condition is true. Entering loop body
41
Loop condition is true. Entering loop body
45
Loop condition is true. Entering loop body
49
Loop condition is false. Execution continues on line 474
468 err = open_ref(ref, path_refs, subdirs[i], refname,
469 lock);
470 if ((err && err->code != GOT_ERR_NOT_REF5) || *ref)
38
Assuming 'err' is null
39
Assuming the condition is false
40
Taking false branch
42
Assuming 'err' is null
43
Assuming the condition is false
44
Taking false branch
46
Assuming 'err' is null
47
Assuming the condition is false
48
Taking false branch
471 goto done;
472 }
473
474 packed_refs_path = got_repo_get_path_packed_refs(repo);
475 if (packed_refs_path == NULL((void *)0)) {
50
Assuming 'packed_refs_path' is not equal to NULL
51
Taking false branch
476 err = got_error_from_errno(
477 "got_repo_get_path_packed_refs");
478 goto done;
479 }
480
481 if (lock
51.1
'lock' is 0
) {
52
Taking false branch
482 err = got_lockfile_lock(&lf, packed_refs_path);
483 if (err)
484 goto done;
485 }
486 f = fopen(packed_refs_path, "rb");
487 free(packed_refs_path);
488 if (f != NULL((void *)0)) {
53
Assuming 'f' is not equal to NULL
54
Taking true branch
489 err = open_packed_ref(ref, f, subdirs, nitems(subdirs)(sizeof(subdirs) / sizeof((subdirs)[0])),
490 refname);
491 if (!err
54.1
'err' is null
) {
55
Taking true branch
492 if (fclose(f) == EOF(-1)) {
56
Assuming the condition is true
57
Taking true branch
493 err = got_error_from_errno("fclose");
494 got_ref_close(*ref);
58
Passing null pointer value via 1st parameter 'ref'
59
Calling 'got_ref_close'
495 *ref = NULL((void *)0);
496 } else if (*ref)
497 (*ref)->lf = lf;
498 }
499 }
500 }
501done:
502 if (!err && *ref == NULL((void *)0))
503 err = got_error_not_ref(refname);
504 if (err && lf)
505 got_lockfile_unlock(lf);
506 free(path_refs);
507 return err;
508}
509
510void
511got_ref_close(struct got_reference *ref)
512{
513 if (ref->flags & GOT_REF_IS_SYMBOLIC0x01) {
60
Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'ref')
514 free(ref->ref.symref.name);
515 free(ref->ref.symref.ref);
516 } else
517 free(ref->ref.ref.name);
518 free(ref);
519}
520
521struct got_reference *
522got_ref_dup(struct got_reference *ref)
523{
524 struct got_reference *ret;
525
526 ret = calloc(1, sizeof(*ret));
527 if (ret == NULL((void *)0))
528 return NULL((void *)0);
529
530 ret->flags = ref->flags;
531 if (ref->flags & GOT_REF_IS_SYMBOLIC0x01) {
532 ret->ref.symref.name = strdup(ref->ref.symref.name);
533 if (ret->ref.symref.name == NULL((void *)0)) {
534 free(ret);
535 return NULL((void *)0);
536 }
537 ret->ref.symref.ref = strdup(ref->ref.symref.ref);
538 if (ret->ref.symref.ref == NULL((void *)0)) {
539 free(ret->ref.symref.name);
540 free(ret);
541 return NULL((void *)0);
542 }
543 } else {
544 ret->ref.ref.name = strdup(ref->ref.ref.name);
545 if (ret->ref.ref.name == NULL((void *)0)) {
546 free(ret);
547 return NULL((void *)0);
548 }
549 memcpy(ret->ref.ref.sha1, ref->ref.ref.sha1,
550 sizeof(ret->ref.ref.sha1));
551 }
552
553 return ret;
554}
555
556const struct got_error *
557got_reflist_entry_dup(struct got_reflist_entry **newp,
558 struct got_reflist_entry *re)
559{
560 const struct got_error *err = NULL((void *)0);
561 struct got_reflist_entry *new;
562
563 *newp = NULL((void *)0);
564
565 new = malloc(sizeof(*new));
566 if (new == NULL((void *)0))
567 return got_error_from_errno("malloc");
568
569 new->ref = got_ref_dup(re->ref);
570 if (new->ref == NULL((void *)0)) {
571 err = got_error_from_errno("got_ref_dup");
572 free(new);
573 return err;
574 }
575
576 *newp = new;
577 return NULL((void *)0);
578}
579
580static const struct got_error *
581resolve_symbolic_ref(struct got_reference **resolved,
582 struct got_repository *repo, struct got_reference *ref)
583{
584 struct got_reference *nextref;
585 const struct got_error *err;
586
587 err = got_ref_open(&nextref, repo, ref->ref.symref.ref, 0);
33
Calling 'got_ref_open'
588 if (err)
589 return err;
590
591 if (nextref->flags & GOT_REF_IS_SYMBOLIC0x01)
592 err = resolve_symbolic_ref(resolved, repo, nextref);
593 else
594 *resolved = got_ref_dup(nextref);
595
596 got_ref_close(nextref);
597 return err;
598}
599
600static const struct got_error *
601ref_resolve(struct got_object_id **id, struct got_repository *repo,
602 struct got_reference *ref, int recursion)
603{
604 const struct got_error *err;
605
606 if (recursion
28.1
'recursion' is > 0
<= 0)
29
Taking false branch
607 return got_error_msg(GOT_ERR_RECURSION32,
608 "reference recursion limit reached");
609
610 if (ref->flags & GOT_REF_IS_SYMBOLIC0x01) {
30
Assuming the condition is true
31
Taking true branch
611 struct got_reference *resolved = NULL((void *)0);
612 err = resolve_symbolic_ref(&resolved, repo, ref);
32
Calling 'resolve_symbolic_ref'
613 if (err == NULL((void *)0))
614 err = ref_resolve(id, repo, resolved, --recursion);
615 if (resolved)
616 got_ref_close(resolved);
617 return err;
618 }
619
620 *id = calloc(1, sizeof(**id));
621 if (*id == NULL((void *)0))
622 return got_error_from_errno("calloc");
623 memcpy((*id)->sha1, ref->ref.ref.sha1, sizeof((*id)->sha1));
624 return NULL((void *)0);
625}
626
627const struct got_error *
628got_ref_resolve(struct got_object_id **id, struct got_repository *repo,
629 struct got_reference *ref)
630{
631 return ref_resolve(id, repo, ref, GOT_REF_RECURSE_MAX20);
28
Calling 'ref_resolve'
632}
633
634char *
635got_ref_to_str(struct got_reference *ref)
636{
637 char *str;
638
639 if (ref->flags & GOT_REF_IS_SYMBOLIC0x01)
640 return strdup(ref->ref.symref.ref);
641
642 str = malloc(SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1));
643 if (str == NULL((void *)0))
644 return NULL((void *)0);
645
646 if (got_sha1_digest_to_str(ref->ref.ref.sha1, str,
647 SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1)) == NULL((void *)0)) {
648 free(str);
649 return NULL((void *)0);
650 }
651
652 return str;
653}
654
655const char *
656got_ref_get_name(struct got_reference *ref)
657{
658 if (ref->flags & GOT_REF_IS_SYMBOLIC0x01)
659 return ref->ref.symref.name;
660
661 return ref->ref.ref.name;
662}
663
664const char *
665got_ref_get_symref_target(struct got_reference *ref)
666{
667 if (ref->flags & GOT_REF_IS_SYMBOLIC0x01)
668 return ref->ref.symref.ref;
669
670 return NULL((void *)0);
671}
672
673const struct got_error *
674got_ref_cmp_by_name(void *arg, int *cmp, struct got_reference *re1,
675 struct got_reference* re2)
676{
677 const char *name1 = got_ref_get_name(re1);
678 const char *name2 = got_ref_get_name(re2);
679
680 *cmp = got_path_cmp(name1, name2, strlen(name1), strlen(name2));
681 return NULL((void *)0);
682}
683
684const struct got_error *
685got_ref_cmp_tags(void *arg, int *cmp, struct got_reference *ref1,
686 struct got_reference *ref2)
687{
688 const struct got_error *err = NULL((void *)0);
689 struct got_repository *repo = arg;
690 struct got_object_id *id1, *id2 = NULL((void *)0);
691 struct got_tag_object *tag1 = NULL((void *)0), *tag2 = NULL((void *)0);
692 struct got_commit_object *commit1 = NULL((void *)0), *commit2 = NULL((void *)0);
693 time_t time1, time2;
694
695 *cmp = 0;
696
697 err = got_ref_resolve(&id1, repo, ref1);
698 if (err)
699 return err;
700 err = got_object_open_as_tag(&tag1, repo, id1);
701 if (err) {
702 if (err->code != GOT_ERR_OBJ_TYPE11)
703 goto done;
704 /* "lightweight" tag */
705 err = got_object_open_as_commit(&commit1, repo, id1);
706 if (err)
707 goto done;
708 time1 = got_object_commit_get_committer_time(commit1);
709 } else
710 time1 = got_object_tag_get_tagger_time(tag1);
711
712 err = got_ref_resolve(&id2, repo, ref2);
713 if (err)
714 goto done;
715 err = got_object_open_as_tag(&tag2, repo, id2);
716 if (err) {
717 if (err->code != GOT_ERR_OBJ_TYPE11)
718 goto done;
719 /* "lightweight" tag */
720 err = got_object_open_as_commit(&commit2, repo, id2);
721 if (err)
722 goto done;
723 time2 = got_object_commit_get_committer_time(commit2);
724 } else
725 time2 = got_object_tag_get_tagger_time(tag2);
726
727 /* Put latest tags first. */
728 if (time1 < time2)
729 *cmp = 1;
730 else if (time1 > time2)
731 *cmp = -1;
732 else
733 err = got_ref_cmp_by_name(NULL((void *)0), cmp, ref2, ref1);
734done:
735 free(id1);
736 free(id2);
737 if (tag1)
738 got_object_tag_close(tag1);
739 if (tag2)
740 got_object_tag_close(tag2);
741 if (commit1)
742 got_object_commit_close(commit1);
743 if (commit2)
744 got_object_commit_close(commit2);
745 return err;
746}
747
748const struct got_error *
749got_ref_cmp_by_commit_timestamp_descending(void *arg, int *cmp,
750 struct got_reference *ref1, struct got_reference *ref2)
751{
752 const struct got_error *err;
753 struct got_repository *repo = arg;
754 struct got_object_id *id1, *id2 = NULL((void *)0);
755 struct got_commit_object *commit1 = NULL((void *)0), *commit2 = NULL((void *)0);
756 time_t time1, time2;
757
758 *cmp = 0;
759
760 err = got_ref_resolve(&id1, repo, ref1);
761 if (err)
762 return err;
763 err = got_ref_resolve(&id2, repo, ref2);
764 if (err)
765 goto done;
766
767 err = got_object_open_as_commit(&commit1, repo, id1);
768 if (err)
769 goto done;
770 err = got_object_open_as_commit(&commit2, repo, id2);
771 if (err)
772 goto done;
773
774 time1 = got_object_commit_get_committer_time(commit1);
775 time2 = got_object_commit_get_committer_time(commit2);
776 if (time1 < time2)
777 *cmp = 1;
778 else if (time2 < time1)
779 *cmp = -1;
780done:
781 free(id1);
782 free(id2);
783 if (commit1)
784 got_object_commit_close(commit1);
785 if (commit2)
786 got_object_commit_close(commit2);
787 return err;
788}
789
790static const struct got_error *
791insert_ref(struct got_reflist_entry **newp, struct got_reflist_head *refs,
792 struct got_reference *ref, struct got_repository *repo,
793 got_ref_cmp_cb cmp_cb, void *cmp_arg)
794{
795 const struct got_error *err;
796 struct got_reflist_entry *new, *re;
797 int cmp;
798
799 *newp = NULL((void *)0);
800
801 new = malloc(sizeof(*new));
802 if (new == NULL((void *)0))
803 return got_error_from_errno("malloc");
804 new->ref = ref;
805 *newp = new;
806
807 /*
808 * We must de-duplicate entries on insert because packed-refs may
809 * contain redundant entries. On-disk refs take precedence.
810 * This code assumes that on-disk revs are read before packed-refs.
811 * We're iterating the list anyway, so insert elements sorted by name.
812 *
813 * Many callers will provide paths in a somewhat sorted order.
814 * Iterating backwards from the tail of the list should be more
815 * efficient than traversing through the entire list each time
816 * an element is inserted.
817 */
818 re = TAILQ_LAST(refs, got_reflist_head)(*(((struct got_reflist_head *)((refs)->tqh_last))->tqh_last
))
;
819 while (re) {
820 err = (*cmp_cb)(cmp_arg, &cmp, re->ref, new->ref);
821 if (err)
822 return err;
823 if (cmp == 0) {
824 /* duplicate */
825 free(new);
826 *newp = NULL((void *)0);
827 return NULL((void *)0);
828 } else if (cmp < 0) {
829 TAILQ_INSERT_AFTER(refs, re, new, entry)do { if (((new)->entry.tqe_next = (re)->entry.tqe_next)
!= ((void *)0)) (new)->entry.tqe_next->entry.tqe_prev =
&(new)->entry.tqe_next; else (refs)->tqh_last = &
(new)->entry.tqe_next; (re)->entry.tqe_next = (new); (new
)->entry.tqe_prev = &(re)->entry.tqe_next; } while (
0)
;
830 return NULL((void *)0);
831 }
832 re = TAILQ_PREV(re, got_reflist_head, entry)(*(((struct got_reflist_head *)((re)->entry.tqe_prev))->
tqh_last))
;
833 }
834
835 TAILQ_INSERT_HEAD(refs, new, entry)do { if (((new)->entry.tqe_next = (refs)->tqh_first) !=
((void *)0)) (refs)->tqh_first->entry.tqe_prev = &
(new)->entry.tqe_next; else (refs)->tqh_last = &(new
)->entry.tqe_next; (refs)->tqh_first = (new); (new)->
entry.tqe_prev = &(refs)->tqh_first; } while (0)
;
836 return NULL((void *)0);
837}
838
839static const struct got_error *
840gather_on_disk_refs(struct got_reflist_head *refs, const char *path_refs,
841 const char *subdir, struct got_repository *repo,
842 got_ref_cmp_cb cmp_cb, void *cmp_arg)
843{
844 const struct got_error *err = NULL((void *)0);
845 DIR *d = NULL((void *)0);
846 char *path_subdir;
847
848 while (subdir[0] == '/')
849 subdir++;
850
851 if (asprintf(&path_subdir, "%s/%s", path_refs, subdir) == -1)
852 return got_error_from_errno("asprintf");
853
854 d = opendir(path_subdir);
855 if (d == NULL((void *)0))
856 goto done;
857
858 for (;;) {
859 struct dirent *dent;
860 struct got_reference *ref;
861 char *child;
862 int type;
863
864 dent = readdir(d);
865 if (dent == NULL((void *)0))
866 break;
867
868 if (strcmp(dent->d_name, ".") == 0 ||
869 strcmp(dent->d_name, "..") == 0)
870 continue;
871
872 err = got_path_dirent_type(&type, path_subdir, dent);
873 if (err)
874 break;
875
876 switch (type) {
877 case DT_REG8:
878 err = open_ref(&ref, path_refs, subdir, dent->d_name,
879 0);
880 if (err)
881 goto done;
882 if (ref) {
883 struct got_reflist_entry *new;
884 err = insert_ref(&new, refs, ref, repo,
885 cmp_cb, cmp_arg);
886 if (err || new == NULL((void *)0) /* duplicate */)
887 got_ref_close(ref);
888 if (err)
889 goto done;
890 }
891 break;
892 case DT_DIR4:
893 if (asprintf(&child, "%s%s%s", subdir,
894 subdir[0] == '\0' ? "" : "/", dent->d_name) == -1) {
895 err = got_error_from_errno("asprintf");
896 break;
897 }
898 err = gather_on_disk_refs(refs, path_refs, child, repo,
899 cmp_cb, cmp_arg);
900 free(child);
901 break;
902 default:
903 break;
904 }
905 }
906done:
907 if (d)
908 closedir(d);
909 free(path_subdir);
910 return err;
911}
912
913const struct got_error *
914got_ref_list(struct got_reflist_head *refs, struct got_repository *repo,
915 const char *ref_namespace, got_ref_cmp_cb cmp_cb, void *cmp_arg)
916{
917 const struct got_error *err;
918 char *packed_refs_path, *path_refs = NULL((void *)0);
919 char *abs_namespace = NULL((void *)0);
920 char *buf = NULL((void *)0), *ondisk_ref_namespace = NULL((void *)0);
921 char *line = NULL((void *)0);
922 FILE *f = NULL((void *)0);
923 struct got_reference *ref;
924 struct got_reflist_entry *new;
925
926 if (ref_namespace == NULL((void *)0) || ref_namespace[0] == '\0') {
927 path_refs = get_refs_dir_path(repo, GOT_REF_HEAD"HEAD");
928 if (path_refs == NULL((void *)0)) {
929 err = got_error_from_errno("get_refs_dir_path");
930 goto done;
931 }
932 err = open_ref(&ref, path_refs, "", GOT_REF_HEAD"HEAD", 0);
933 if (err)
934 goto done;
935 err = insert_ref(&new, refs, ref, repo,
936 cmp_cb, cmp_arg);
937 if (err || new == NULL((void *)0) /* duplicate */)
938 got_ref_close(ref);
939 if (err && err->code != GOT_ERR_NOT_REF5)
940 goto done;
941 } else {
942 /* Try listing a single reference. */
943 const char *refname = ref_namespace;
944 path_refs = get_refs_dir_path(repo, refname);
945 if (path_refs == NULL((void *)0)) {
946 err = got_error_from_errno("get_refs_dir_path");
947 goto done;
948 }
949 err = open_ref(&ref, path_refs, "", refname, 0);
950 if (err) {
951 if (err->code != GOT_ERR_NOT_REF5)
952 goto done;
953 /* Try to look up references in a given namespace. */
954 } else {
955 err = insert_ref(&new, refs, ref, repo,
956 cmp_cb, cmp_arg);
957 if (err || new == NULL((void *)0) /* duplicate */)
958 got_ref_close(ref);
959 return err;
960 }
961 }
962
963 if (ref_namespace) {
964 size_t len;
965 /* Canonicalize the path to eliminate double-slashes if any. */
966 if (asprintf(&abs_namespace, "/%s", ref_namespace) == -1) {
967 err = got_error_from_errno("asprintf");
968 goto done;
969 }
970 len = strlen(abs_namespace) + 1;
971 buf = malloc(len);
972 if (buf == NULL((void *)0)) {
973 err = got_error_from_errno("malloc");
974 goto done;
975 }
976 err = got_canonpath(abs_namespace, buf, len);
977 if (err)
978 goto done;
979 ondisk_ref_namespace = buf;
980 while (ondisk_ref_namespace[0] == '/')
981 ondisk_ref_namespace++;
982 if (strncmp(ondisk_ref_namespace, "refs/", 5) == 0)
983 ondisk_ref_namespace += 5;
984 else if (strcmp(ondisk_ref_namespace, "refs") == 0)
985 ondisk_ref_namespace = "";
986 }
987
988 /* Gather on-disk refs before parsing packed-refs. */
989 free(path_refs);
990 path_refs = get_refs_dir_path(repo, "");
991 if (path_refs == NULL((void *)0)) {
992 err = got_error_from_errno("get_refs_dir_path");
993 goto done;
994 }
995 err = gather_on_disk_refs(refs, path_refs,
996 ondisk_ref_namespace ? ondisk_ref_namespace : "", repo,
997 cmp_cb, cmp_arg);
998 if (err)
999 goto done;
1000
1001 /*
1002 * The packed-refs file may contain redundant entries, in which
1003 * case on-disk refs take precedence.
1004 */
1005 packed_refs_path = got_repo_get_path_packed_refs(repo);
1006 if (packed_refs_path == NULL((void *)0)) {
1007 err = got_error_from_errno("got_repo_get_path_packed_refs");
1008 goto done;
1009 }
1010
1011 f = fopen(packed_refs_path, "r");
1012 free(packed_refs_path);
1013 if (f) {
1014 size_t linesize = 0;
1015 ssize_t linelen;
1016 for (;;) {
1017 linelen = getline(&line, &linesize, f);
1018 if (linelen == -1) {
1019 if (feof(f)(!__isthreaded ? (((f)->_flags & 0x0020) != 0) : (feof
)(f))
)
1020 break;
1021 err = got_ferror(f, GOT_ERR_BAD_REF_DATA57);
1022 goto done;
1023 }
1024 if (linelen > 0 && line[linelen - 1] == '\n')
1025 line[linelen - 1] = '\0';
1026 err = parse_packed_ref_line(&ref, NULL((void *)0), line);
1027 if (err)
1028 goto done;
1029 if (ref) {
1030 if (ref_namespace) {
1031 const char *name;
1032 name = got_ref_get_name(ref);
1033 if (!got_path_is_child(name,
1034 ref_namespace,
1035 strlen(ref_namespace))) {
1036 got_ref_close(ref);
1037 continue;
1038 }
1039 }
1040 err = insert_ref(&new, refs, ref, repo,
1041 cmp_cb, cmp_arg);
1042 if (err || new == NULL((void *)0) /* duplicate */)
1043 got_ref_close(ref);
1044 if (err)
1045 goto done;
1046 }
1047 }
1048 }
1049done:
1050 free(abs_namespace);
1051 free(buf);
1052 free(line);
1053 free(path_refs);
1054 if (f && fclose(f) == EOF(-1) && err == NULL((void *)0))
1055 err = got_error_from_errno("fclose");
1056 return err;
1057}
1058
1059void
1060got_ref_list_free(struct got_reflist_head *refs)
1061{
1062 struct got_reflist_entry *re;
1063
1064 while ((re = TAILQ_FIRST(refs)((refs)->tqh_first))) {
1065 TAILQ_REMOVE(refs, re, entry)do { if (((re)->entry.tqe_next) != ((void *)0)) (re)->entry
.tqe_next->entry.tqe_prev = (re)->entry.tqe_prev; else (
refs)->tqh_last = (re)->entry.tqe_prev; *(re)->entry
.tqe_prev = (re)->entry.tqe_next; ; ; } while (0)
;
1066 got_ref_close(re->ref);
1067 free(re);
1068 }
1069
1070}
1071
1072int
1073got_ref_is_symbolic(struct got_reference *ref)
1074{
1075 return (ref->flags & GOT_REF_IS_SYMBOLIC0x01);
1076}
1077
1078const struct got_error *
1079got_ref_change_ref(struct got_reference *ref, struct got_object_id *id)
1080{
1081 if (ref->flags & GOT_REF_IS_SYMBOLIC0x01)
1082 return got_error(GOT_ERR_BAD_REF_TYPE70);
1083
1084 memcpy(ref->ref.ref.sha1, id->sha1, sizeof(ref->ref.ref.sha1));
1085 return NULL((void *)0);
1086}
1087
1088const struct got_error *
1089got_ref_change_symref(struct got_reference *ref, const char *refname)
1090{
1091 char *new_name;
1092
1093 if ((ref->flags & GOT_REF_IS_SYMBOLIC0x01) == 0)
1094 return got_error(GOT_ERR_BAD_REF_TYPE70);
1095
1096 new_name = strdup(refname);
1097 if (new_name == NULL((void *)0))
1098 return got_error_from_errno("strdup");
1099
1100 free(ref->ref.symref.ref);
1101 ref->ref.symref.ref = new_name;
1102 return NULL((void *)0);
1103}
1104
1105const struct got_error *
1106got_ref_change_symref_to_ref(struct got_reference *symref,
1107 struct got_object_id *id)
1108{
1109 if ((symref->flags & GOT_REF_IS_SYMBOLIC0x01) == 0)
1110 return got_error(GOT_ERR_BAD_REF_TYPE70);
1111
1112 symref->ref.ref.name = symref->ref.symref.name;
1113 memcpy(symref->ref.ref.sha1, id->sha1, SHA1_DIGEST_LENGTH20);
1114 symref->flags &= ~GOT_REF_IS_SYMBOLIC0x01;
1115 return NULL((void *)0);
1116}
1117
1118const struct got_error *
1119got_ref_write(struct got_reference *ref, struct got_repository *repo)
1120{
1121 const struct got_error *err = NULL((void *)0), *unlock_err = NULL((void *)0);
1122 const char *name = got_ref_get_name(ref);
1123 char *path_refs = NULL((void *)0), *path = NULL((void *)0), *tmppath = NULL((void *)0);
1124 struct got_lockfile *lf = NULL((void *)0);
1125 FILE *f = NULL((void *)0);
1126 size_t n;
1127 struct stat sb;
1128
1129 path_refs = get_refs_dir_path(repo, name);
1130 if (path_refs == NULL((void *)0)) {
1131 err = got_error_from_errno2("get_refs_dir_path", name);
1132 goto done;
1133 }
1134
1135 if (asprintf(&path, "%s/%s", path_refs, name) == -1) {
1136 err = got_error_from_errno("asprintf");
1137 goto done;
1138 }
1139
1140 err = got_opentemp_named(&tmppath, &f, path);
1141 if (err) {
1142 char *parent;
1143 if (!(err->code == GOT_ERR_ERRNO1 && errno(*__errno()) == ENOENT2))
1144 goto done;
1145 err = got_path_dirname(&parent, path);
1146 if (err)
1147 goto done;
1148 err = got_path_mkdir(parent);
1149 free(parent);
1150 if (err)
1151 goto done;
1152 err = got_opentemp_named(&tmppath, &f, path);
1153 if (err)
1154 goto done;
1155 }
1156
1157 if (ref->flags & GOT_REF_IS_SYMBOLIC0x01) {
1158 n = fprintf(f, "ref: %s\n", ref->ref.symref.ref);
1159 if (n != strlen(ref->ref.symref.ref) + 6) {
1160 err = got_ferror(f, GOT_ERR_IO6);
1161 goto done;
1162 }
1163 } else {
1164 char hex[SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1)];
1165 if (got_sha1_digest_to_str(ref->ref.ref.sha1, hex,
1166 sizeof(hex)) == NULL((void *)0)) {
1167 err = got_error(GOT_ERR_BAD_REF_DATA57);
1168 goto done;
1169 }
1170 n = fprintf(f, "%s\n", hex);
1171 if (n != sizeof(hex)) {
1172 err = got_ferror(f, GOT_ERR_IO6);
1173 goto done;
1174 }
1175 }
1176
1177 if (ref->lf == NULL((void *)0)) {
1178 err = got_lockfile_lock(&lf, path);
1179 if (err)
1180 goto done;
1181 }
1182
1183 /* XXX: check if old content matches our expectations? */
1184
1185 if (stat(path, &sb) != 0) {
1186 if (errno(*__errno()) != ENOENT2) {
1187 err = got_error_from_errno2("stat", path);
1188 goto done;
1189 }
1190 sb.st_mode = GOT_DEFAULT_FILE_MODE(0100000 | 0000400|0000200 | 0000040 | 0000004);
1191 }
1192
1193 if (fchmod(fileno(f)(!__isthreaded ? ((f)->_file) : (fileno)(f)), sb.st_mode) != 0) {
1194 err = got_error_from_errno2("fchmod", tmppath);
1195 goto done;
1196 }
1197
1198 if (rename(tmppath, path) != 0) {
1199 err = got_error_from_errno3("rename", tmppath, path);
1200 goto done;
1201 }
1202 free(tmppath);
1203 tmppath = NULL((void *)0);
1204done:
1205 if (ref->lf == NULL((void *)0) && lf)
1206 unlock_err = got_lockfile_unlock(lf);
1207 if (f) {
1208 if (fclose(f) == EOF(-1) && err == NULL((void *)0))
1209 err = got_error_from_errno("fclose");
1210 }
1211 free(path_refs);
1212 free(path);
1213 if (tmppath) {
1214 if (unlink(tmppath) != 0 && err == NULL((void *)0))
1215 err = got_error_from_errno2("unlink", tmppath);
1216 free(tmppath);
1217 }
1218 return err ? err : unlock_err;
1219}
1220
1221static const struct got_error *
1222delete_packed_ref(struct got_reference *delref, struct got_repository *repo)
1223{
1224 const struct got_error *err = NULL((void *)0), *unlock_err = NULL((void *)0);
1225 struct got_lockfile *lf = NULL((void *)0);
1226 FILE *f = NULL((void *)0), *tmpf = NULL((void *)0);
1227 char *line = NULL((void *)0), *packed_refs_path, *tmppath = NULL((void *)0);
1228 size_t linesize = 0;
1229 struct got_reflist_head refs;
1230 int found_delref = 0;
1231
1232 /* The packed-refs file does not cotain symbolic references. */
1233 if (delref->flags & GOT_REF_IS_SYMBOLIC0x01)
1234 return got_error(GOT_ERR_BAD_REF_DATA57);
1235
1236 TAILQ_INIT(&refs)do { (&refs)->tqh_first = ((void *)0); (&refs)->
tqh_last = &(&refs)->tqh_first; } while (0)
;
1237
1238 packed_refs_path = got_repo_get_path_packed_refs(repo);
1239 if (packed_refs_path == NULL((void *)0))
1240 return got_error_from_errno("got_repo_get_path_packed_refs");
1241
1242 err = got_opentemp_named(&tmppath, &tmpf, packed_refs_path);
1243 if (err)
1244 goto done;
1245
1246 if (delref->lf == NULL((void *)0)) {
1247 err = got_lockfile_lock(&lf, packed_refs_path);
1248 if (err)
1249 goto done;
1250 }
1251
1252 f = fopen(packed_refs_path, "r");
1253 if (f == NULL((void *)0)) {
1254 err = got_error_from_errno2("fopen", packed_refs_path);
1255 goto done;
1256 }
1257 for (;;) {
1258 ssize_t linelen;
1259 struct got_reference *ref;
1260 struct got_reflist_entry *new;
1261
1262 linelen = getline(&line, &linesize, f);
1263 if (linelen == -1) {
1264 if (feof(f)(!__isthreaded ? (((f)->_flags & 0x0020) != 0) : (feof
)(f))
)
1265 break;
1266 err = got_ferror(f, GOT_ERR_BAD_REF_DATA57);
1267 goto done;
1268 }
1269 if (linelen > 0 && line[linelen - 1] == '\n')
1270 line[linelen - 1] = '\0';
1271 err = parse_packed_ref_line(&ref, NULL((void *)0), line);
1272 if (err)
1273 goto done;
1274 if (ref == NULL((void *)0))
1275 continue;
1276
1277 if (strcmp(ref->ref.ref.name, delref->ref.ref.name) == 0 &&
1278 memcmp(ref->ref.ref.sha1, delref->ref.ref.sha1,
1279 sizeof(delref->ref.ref.sha1)) == 0) {
1280 found_delref = 1;
1281 got_ref_close(ref);
1282 continue;
1283 }
1284
1285 err = insert_ref(&new, &refs, ref, repo,
1286 got_ref_cmp_by_name, NULL((void *)0));
1287 if (err || new == NULL((void *)0) /* duplicate */)
1288 got_ref_close(ref);
1289 if (err)
1290 goto done;
1291 }
1292
1293 if (found_delref) {
1294 struct got_reflist_entry *re;
1295 size_t n;
1296 struct stat sb;
1297
1298 n = fprintf(tmpf, "%s\n", GOT_PACKED_REFS_HEADER"# pack-refs with:");
1299 if (n != sizeof(GOT_PACKED_REFS_HEADER"# pack-refs with:")) {
1300 err = got_ferror(f, GOT_ERR_IO6);
1301 goto done;
1302 }
1303
1304 TAILQ_FOREACH(re, &refs, entry)for((re) = ((&refs)->tqh_first); (re) != ((void *)0); (
re) = ((re)->entry.tqe_next))
{
1305 uint8_t hex[SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1)];
1306
1307 if (got_sha1_digest_to_str(re->ref->ref.ref.sha1, hex,
1308 sizeof(hex)) == NULL((void *)0)) {
1309 err = got_error(GOT_ERR_BAD_REF_DATA57);
1310 goto done;
1311 }
1312 n = fprintf(tmpf, "%s ", hex);
1313 if (n != sizeof(hex)) {
1314 err = got_ferror(f, GOT_ERR_IO6);
1315 goto done;
1316 }
1317 n = fprintf(tmpf, "%s\n", re->ref->ref.ref.name);
1318 if (n != strlen(re->ref->ref.ref.name) + 1) {
1319 err = got_ferror(f, GOT_ERR_IO6);
1320 goto done;
1321 }
1322 }
1323
1324 if (fflush(tmpf) != 0) {
1325 err = got_error_from_errno("fflush");
1326 goto done;
1327 }
1328
1329 if (fstat(fileno(f)(!__isthreaded ? ((f)->_file) : (fileno)(f)), &sb) != 0) {
1330 if (errno(*__errno()) != ENOENT2) {
1331 err = got_error_from_errno2("fstat",
1332 packed_refs_path);
1333 goto done;
1334 }
1335 sb.st_mode = GOT_DEFAULT_FILE_MODE(0100000 | 0000400|0000200 | 0000040 | 0000004);
1336 }
1337
1338 if (fchmod(fileno(tmpf)(!__isthreaded ? ((tmpf)->_file) : (fileno)(tmpf)), sb.st_mode) != 0) {
1339 err = got_error_from_errno2("fchmod", tmppath);
1340 goto done;
1341 }
1342
1343 if (rename(tmppath, packed_refs_path) != 0) {
1344 err = got_error_from_errno3("rename", tmppath,
1345 packed_refs_path);
1346 goto done;
1347 }
1348 }
1349done:
1350 if (delref->lf == NULL((void *)0) && lf)
1351 unlock_err = got_lockfile_unlock(lf);
1352 if (f) {
1353 if (fclose(f) == EOF(-1) && err == NULL((void *)0))
1354 err = got_error_from_errno("fclose");
1355 }
1356 if (tmpf) {
1357 unlink(tmppath);
1358 if (fclose(tmpf) == EOF(-1) && err == NULL((void *)0))
1359 err = got_error_from_errno("fclose");
1360 }
1361 free(tmppath);
1362 free(packed_refs_path);
1363 free(line);
1364 got_ref_list_free(&refs);
1365 return err ? err : unlock_err;
1366}
1367
1368static const struct got_error *
1369delete_loose_ref(struct got_reference *ref, struct got_repository *repo)
1370{
1371 const struct got_error *err = NULL((void *)0), *unlock_err = NULL((void *)0);
1372 const char *name = got_ref_get_name(ref);
1373 char *path_refs = NULL((void *)0), *path = NULL((void *)0);
1374 struct got_lockfile *lf = NULL((void *)0);
1375
1376 path_refs = get_refs_dir_path(repo, name);
1377 if (path_refs == NULL((void *)0)) {
1378 err = got_error_from_errno2("get_refs_dir_path", name);
1379 goto done;
1380 }
1381
1382 if (asprintf(&path, "%s/%s", path_refs, name) == -1) {
1383 err = got_error_from_errno("asprintf");
1384 goto done;
1385 }
1386
1387 if (ref->lf == NULL((void *)0)) {
1388 err = got_lockfile_lock(&lf, path);
1389 if (err)
1390 goto done;
1391 }
1392
1393 /* XXX: check if old content matches our expectations? */
1394
1395 if (unlink(path) != 0)
1396 err = got_error_from_errno2("unlink", path);
1397done:
1398 if (ref->lf == NULL((void *)0) && lf)
1399 unlock_err = got_lockfile_unlock(lf);
1400
1401 free(path_refs);
1402 free(path);
1403 return err ? err : unlock_err;
1404}
1405
1406const struct got_error *
1407got_ref_delete(struct got_reference *ref, struct got_repository *repo)
1408{
1409 const struct got_error *err = NULL((void *)0);
1410 struct got_reference *ref2;
1411
1412 if (ref->flags & GOT_REF_IS_PACKED0x02) {
1413 err = delete_packed_ref(ref, repo);
1414 if (err)
1415 return err;
1416
1417 err = got_ref_open(&ref2, repo, got_ref_get_name(ref), 0);
1418 if (err) {
1419 if (err->code == GOT_ERR_NOT_REF5)
1420 return NULL((void *)0);
1421 return err;
1422 }
1423
1424 err = delete_loose_ref(ref2, repo);
1425 got_ref_close(ref2);
1426 return err;
1427 } else {
1428 err = delete_loose_ref(ref, repo);
1429 if (err)
1430 return err;
1431
1432 err = got_ref_open(&ref2, repo, got_ref_get_name(ref), 0);
1433 if (err) {
1434 if (err->code == GOT_ERR_NOT_REF5)
1435 return NULL((void *)0);
1436 return err;
1437 }
1438
1439 err = delete_packed_ref(ref2, repo);
1440 got_ref_close(ref2);
1441 return err;
1442 }
1443}
1444
1445const struct got_error *
1446got_ref_unlock(struct got_reference *ref)
1447{
1448 const struct got_error *err;
1449 err = got_lockfile_unlock(ref->lf);
1450 ref->lf = NULL((void *)0);
1451 return err;
1452}
1453
1454struct got_reflist_object_id_map {
1455 struct got_object_idset *idset;
1456};
1457
1458struct got_reflist_object_id_map_entry {
1459 struct got_reflist_head refs;
1460};
1461
1462static const struct got_error *
1463add_object_id_map_entry(struct got_object_idset *idset,
1464 struct got_object_id *id, struct got_reflist_entry *re)
1465{
1466 const struct got_error *err = NULL((void *)0);
1467 struct got_reflist_object_id_map_entry *ent;
1468 struct got_reflist_entry *new;
1469
1470 ent = got_object_idset_get(idset, id);
1471 if (ent == NULL((void *)0)) {
1472 ent = malloc(sizeof(*ent));
1473 if (ent == NULL((void *)0))
1474 return got_error_from_errno("malloc");
1475
1476 TAILQ_INIT(&ent->refs)do { (&ent->refs)->tqh_first = ((void *)0); (&ent
->refs)->tqh_last = &(&ent->refs)->tqh_first
; } while (0)
;
1477 err = got_object_idset_add(idset, id, ent);
1478 if (err)
1479 return err;
1480 }
1481
1482 err = got_reflist_entry_dup(&new, re);
1483 if (err)
1484 return err;
1485
1486 TAILQ_INSERT_TAIL(&ent->refs, new, entry)do { (new)->entry.tqe_next = ((void *)0); (new)->entry.
tqe_prev = (&ent->refs)->tqh_last; *(&ent->refs
)->tqh_last = (new); (&ent->refs)->tqh_last = &
(new)->entry.tqe_next; } while (0)
;
1487 return NULL((void *)0);
1488}
1489
1490const struct got_error *
1491got_reflist_object_id_map_create(struct got_reflist_object_id_map **map,
1492 struct got_reflist_head *refs, struct got_repository *repo)
1493{
1494 const struct got_error *err = NULL((void *)0);
1495 struct got_object_idset *idset;
1496 struct got_object_id *id = NULL((void *)0);
1497 struct got_reflist_entry *re;
1498
1499 idset = got_object_idset_alloc();
1500 if (idset == NULL((void *)0))
1
Assuming 'idset' is not equal to NULL
2
Taking false branch
1501 return got_error_from_errno("got_object_idset_alloc");
1502
1503 *map = malloc(sizeof(**map));
1504 if (*map == NULL((void *)0)) {
3
Assuming the condition is false
4
Taking false branch
1505 got_object_idset_free(idset);
1506 return got_error_from_errno("malloc");
1507 }
1508 (*map)->idset = idset;
1509
1510 TAILQ_FOREACH(re, refs, entry)for((re) = ((refs)->tqh_first); (re) != ((void *)0); (re) =
((re)->entry.tqe_next))
{
5
Assuming 're' is not equal to null
6
Loop condition is true. Entering loop body
17
Assuming 're' is not equal to null
18
Loop condition is true. Entering loop body
25
Assuming 're' is not equal to null
26
Loop condition is true. Entering loop body
1511 struct got_tag_object *tag = NULL((void *)0);
1512
1513 err = got_ref_resolve(&id, repo, re->ref);
27
Calling 'got_ref_resolve'
1514 if (err
6.1
'err' is null
)
7
Taking false branch
19
Assuming 'err' is null
20
Taking false branch
1515 goto done;
1516
1517 err = add_object_id_map_entry(idset, id, re);
1518 if (err
20.1
'err' is null
)
8
Assuming 'err' is null
9
Taking false branch
21
Taking false branch
1519 goto done;
1520
1521 if (strstr(got_ref_get_name(re->ref), "/tags/") == NULL((void *)0)) {
10
Assuming the condition is false
11
Taking false branch
22
Assuming the condition is true
23
Taking true branch
1522 free(id);
1523 id = NULL((void *)0);
1524 continue;
24
Execution continues on line 1510
1525 }
1526
1527 err = got_object_open_as_tag(&tag, repo, id);
1528 if (err) {
12
Assuming 'err' is non-null
13
Taking true branch
1529 if (err->code != GOT_ERR_OBJ_TYPE11)
14
Assuming field 'code' is equal to GOT_ERR_OBJ_TYPE
15
Taking false branch
1530 goto done;
1531 /* Ref points at something other than a tag. */
1532 err = NULL((void *)0);
1533 tag = NULL((void *)0);
1534 free(id);
1535 id = NULL((void *)0);
1536 continue;
16
Execution continues on line 1510
1537 }
1538
1539 err = add_object_id_map_entry(idset,
1540 got_object_tag_get_object_id(tag), re);
1541 got_object_tag_close(tag);
1542 if (err)
1543 goto done;
1544
1545 free(id);
1546 id = NULL((void *)0);
1547 }
1548done:
1549 free(id);
1550 if (err) {
1551 got_reflist_object_id_map_free(*map);
1552 *map = NULL((void *)0);
1553 }
1554 return err;
1555}
1556
1557struct got_reflist_head *
1558got_reflist_object_id_map_lookup(struct got_reflist_object_id_map *map,
1559 struct got_object_id *id)
1560{
1561 struct got_reflist_object_id_map_entry *ent;
1562 ent = got_object_idset_get(map->idset, id);
1563 if (ent)
1564 return &ent->refs;
1565 return NULL((void *)0);
1566}
1567
1568static const struct got_error *
1569free_id_map_entry(struct got_object_id *id, void *data, void *arg)
1570{
1571 struct got_reflist_object_id_map_entry *ent = data;
1572
1573 got_ref_list_free(&ent->refs);
1574 free(ent);
1575 return NULL((void *)0);
1576}
1577
1578void
1579got_reflist_object_id_map_free(struct got_reflist_object_id_map *map)
1580{
1581 got_object_idset_for_each(map->idset, free_id_map_entry, NULL((void *)0));
1582 got_object_idset_free(map->idset);
1583 free(map);
1584}