Blob


1 #include <sys/types.h>
2 #include <sha1.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <util.h>
8 #include "got_error.h"
9 #include "got_path.h"
10 #include "got_refs.h"
12 static const struct got_error *
13 parse_symref(struct got_reference **ref, const char *name, const char *line)
14 {
15 struct got_symref *symref;
16 char *symref_name;
17 char *symref_ref;
19 if (line[0] == '\0')
20 return got_error(GOT_ERR_NOT_REF);
22 symref_name = strdup(name);
23 if (symref_name == NULL)
24 return got_error(GOT_ERR_NO_MEM);
25 symref_ref = strdup(line);
26 if (symref_ref == NULL) {
27 free(symref_name);
28 return got_error(GOT_ERR_NO_MEM);
29 }
31 *ref = calloc(1, sizeof(**ref));
32 (*ref)->flags |= GOT_REF_IS_SYMBOLIC;
33 symref = &((*ref)->ref.symref);
34 symref->name = symref_name;
35 symref->ref = symref_ref;
36 return NULL;
37 }
39 static int
40 parse_sha1_digest(uint8_t *digest, const char *line)
41 {
42 uint8_t b;
43 int i, n;
45 for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
46 n = sscanf(line, "%hhx", &b);
47 if (n == 1)
48 digest[i] = b;
49 else
50 return 0;
51 }
53 return 1;
54 }
56 static const struct got_error *
57 parse_ref_line(struct got_reference **ref, const char *name, const char *line)
58 {
59 uint8_t digest[SHA1_DIGEST_LENGTH];
60 char *ref_name;
62 if (strncmp(line, "ref: ", 5) == 0) {
63 line += 5;
64 return parse_symref(ref, name, line);
65 }
67 ref_name = strdup(name);
68 if (ref_name == NULL)
69 return got_error(GOT_ERR_NO_MEM);
71 if (!parse_sha1_digest(digest, line))
72 return got_error(GOT_ERR_NOT_REF);
74 *ref = calloc(1, sizeof(**ref));
75 (*ref)->ref.ref.name = ref_name;
76 memcpy(&(*ref)->ref.ref.sha1, digest, SHA1_DIGEST_LENGTH);
77 return NULL;
78 }
80 static const struct got_error *
81 parse_ref_file(struct got_reference **ref, const char *name,
82 const char *abspath)
83 {
84 const struct got_error *err = NULL;
85 FILE *f = fopen(abspath, "rb");
86 char *line;
87 size_t len;
88 const char delim[3] = {'\0', '\0', '\0'};
90 if (f == NULL)
91 return got_error(GOT_ERR_NOT_REF);
93 line = fparseln(f, &len, NULL, delim, 0);
94 if (line == NULL) {
95 err = got_error(GOT_ERR_NOT_REF);
96 goto done;
97 }
99 err = parse_ref_line(ref, name, line);
100 done:
101 free(line);
102 fclose(f);
103 return err;
106 const struct got_error *
107 got_ref_open(struct got_reference **ref, const char *path_refs,
108 const char *refname)
110 const struct got_error *err = NULL;
111 char *path_ref = NULL;
112 char *normpath = NULL;
113 const char *parent_dir;
115 /* XXX For now, this assumes that refs exist in the filesystem. */
117 if (asprintf(&path_ref, "%s/%s", path_refs, refname) == -1) {
118 err = got_error(GOT_ERR_NO_MEM);
119 goto done;
122 normpath = got_path_normalize(path_ref);
123 if (normpath == NULL) {
124 err = got_error(GOT_ERR_NOT_REF);
125 goto done;
128 err = parse_ref_file(ref, refname, normpath ? normpath : path_refs);
129 done:
130 free(normpath);
131 free(path_ref);
132 return err;
135 void
136 got_ref_close(struct got_reference *ref)
138 if (ref->flags & GOT_REF_IS_SYMBOLIC)
139 free(ref->ref.symref.name);
140 else
141 free(ref->ref.ref.name);
142 free(ref);