Blame


1 bd3d9e54 2021-09-05 stsp /*
2 bd3d9e54 2021-09-05 stsp * Copyright (c) 2019 Ori Bernstein <ori@openbsd.org>
3 bd3d9e54 2021-09-05 stsp * Copyright (c) 2021 Stefan Sperling <stsp@openbsd.org>
4 bd3d9e54 2021-09-05 stsp *
5 bd3d9e54 2021-09-05 stsp * Permission to use, copy, modify, and distribute this software for any
6 bd3d9e54 2021-09-05 stsp * purpose with or without fee is hereby granted, provided that the above
7 bd3d9e54 2021-09-05 stsp * copyright notice and this permission notice appear in all copies.
8 bd3d9e54 2021-09-05 stsp *
9 bd3d9e54 2021-09-05 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 bd3d9e54 2021-09-05 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 bd3d9e54 2021-09-05 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 bd3d9e54 2021-09-05 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 bd3d9e54 2021-09-05 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 bd3d9e54 2021-09-05 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 bd3d9e54 2021-09-05 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 bd3d9e54 2021-09-05 stsp */
17 4fccd2fe 2023-03-08 thomas
18 4fccd2fe 2023-03-08 thomas #include "got_compat.h"
19 bd3d9e54 2021-09-05 stsp
20 8b925c6c 2022-07-16 thomas #include <sys/queue.h>
21 8a8621c2 2021-09-06 naddy #include <sys/types.h>
22 bd3d9e54 2021-09-05 stsp
23 bd3d9e54 2021-09-05 stsp #include <ctype.h>
24 bd3d9e54 2021-09-05 stsp #include <stdio.h>
25 bd3d9e54 2021-09-05 stsp #include <stdlib.h>
26 bd3d9e54 2021-09-05 stsp #include <string.h>
27 bd3d9e54 2021-09-05 stsp
28 bd3d9e54 2021-09-05 stsp #include "got_error.h"
29 bd3d9e54 2021-09-05 stsp #include "got_path.h"
30 bd3d9e54 2021-09-05 stsp
31 bd3d9e54 2021-09-05 stsp #include "got_lib_gitproto.h"
32 bd3d9e54 2021-09-05 stsp
33 bd3d9e54 2021-09-05 stsp #ifndef nitems
34 bd3d9e54 2021-09-05 stsp #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
35 bd3d9e54 2021-09-05 stsp #endif
36 bd3d9e54 2021-09-05 stsp
37 3efd8e31 2022-10-23 thomas static void
38 3efd8e31 2022-10-23 thomas free_tokens(char **tokens, size_t ntokens)
39 3efd8e31 2022-10-23 thomas {
40 3efd8e31 2022-10-23 thomas int i;
41 3efd8e31 2022-10-23 thomas
42 3efd8e31 2022-10-23 thomas for (i = 0; i < ntokens; i++) {
43 3efd8e31 2022-10-23 thomas free(tokens[i]);
44 3efd8e31 2022-10-23 thomas tokens[i] = NULL;
45 3efd8e31 2022-10-23 thomas }
46 3efd8e31 2022-10-23 thomas }
47 3efd8e31 2022-10-23 thomas
48 bd3d9e54 2021-09-05 stsp static const struct got_error *
49 3efd8e31 2022-10-23 thomas tokenize_line(char **tokens, char *line, int len, int mintokens, int maxtokens)
50 bd3d9e54 2021-09-05 stsp {
51 bd3d9e54 2021-09-05 stsp const struct got_error *err = NULL;
52 bd3d9e54 2021-09-05 stsp char *p;
53 bd3d9e54 2021-09-05 stsp size_t i, n = 0;
54 bd3d9e54 2021-09-05 stsp
55 bd3d9e54 2021-09-05 stsp for (i = 0; i < maxtokens; i++)
56 bd3d9e54 2021-09-05 stsp tokens[i] = NULL;
57 bd3d9e54 2021-09-05 stsp
58 bd3d9e54 2021-09-05 stsp for (i = 0; n < len && i < maxtokens; i++) {
59 693bff59 2023-01-19 thomas while (n < len && isspace((unsigned char)*line)) {
60 bd3d9e54 2021-09-05 stsp line++;
61 bd3d9e54 2021-09-05 stsp n++;
62 bd3d9e54 2021-09-05 stsp }
63 bd3d9e54 2021-09-05 stsp p = line;
64 bd3d9e54 2021-09-05 stsp while (*line != '\0' && n < len &&
65 6771d425 2022-11-17 thomas (!isspace((unsigned char)*line) || i == maxtokens - 1)) {
66 bd3d9e54 2021-09-05 stsp line++;
67 bd3d9e54 2021-09-05 stsp n++;
68 bd3d9e54 2021-09-05 stsp }
69 bd3d9e54 2021-09-05 stsp tokens[i] = strndup(p, line - p);
70 bd3d9e54 2021-09-05 stsp if (tokens[i] == NULL) {
71 bd3d9e54 2021-09-05 stsp err = got_error_from_errno("strndup");
72 bd3d9e54 2021-09-05 stsp goto done;
73 bd3d9e54 2021-09-05 stsp }
74 bd3d9e54 2021-09-05 stsp /* Skip \0 field-delimiter at end of token. */
75 bd3d9e54 2021-09-05 stsp while (line[0] == '\0' && n < len) {
76 bd3d9e54 2021-09-05 stsp line++;
77 bd3d9e54 2021-09-05 stsp n++;
78 bd3d9e54 2021-09-05 stsp }
79 bd3d9e54 2021-09-05 stsp }
80 3efd8e31 2022-10-23 thomas if (i < mintokens)
81 3efd8e31 2022-10-23 thomas err = got_error_msg(GOT_ERR_BAD_PACKET,
82 3efd8e31 2022-10-23 thomas "pkt-line contains too few tokens");
83 bd3d9e54 2021-09-05 stsp done:
84 3efd8e31 2022-10-23 thomas if (err)
85 3efd8e31 2022-10-23 thomas free_tokens(tokens, i);
86 bd3d9e54 2021-09-05 stsp return err;
87 bd3d9e54 2021-09-05 stsp }
88 bd3d9e54 2021-09-05 stsp
89 bd3d9e54 2021-09-05 stsp const struct got_error *
90 bd3d9e54 2021-09-05 stsp got_gitproto_parse_refline(char **id_str, char **refname,
91 bd3d9e54 2021-09-05 stsp char **server_capabilities, char *line, int len)
92 bd3d9e54 2021-09-05 stsp {
93 bd3d9e54 2021-09-05 stsp const struct got_error *err = NULL;
94 bd3d9e54 2021-09-05 stsp char *tokens[3];
95 bd3d9e54 2021-09-05 stsp
96 35add24a 2021-10-08 thomas *id_str = NULL;
97 35add24a 2021-10-08 thomas *refname = NULL;
98 35add24a 2021-10-08 thomas /* don't reset *server_capabilities */
99 35add24a 2021-10-08 thomas
100 3efd8e31 2022-10-23 thomas err = tokenize_line(tokens, line, len, 2, nitems(tokens));
101 bd3d9e54 2021-09-05 stsp if (err)
102 bd3d9e54 2021-09-05 stsp return err;
103 bd3d9e54 2021-09-05 stsp
104 bd3d9e54 2021-09-05 stsp if (tokens[0])
105 bd3d9e54 2021-09-05 stsp *id_str = tokens[0];
106 bd3d9e54 2021-09-05 stsp if (tokens[1])
107 bd3d9e54 2021-09-05 stsp *refname = tokens[1];
108 bd3d9e54 2021-09-05 stsp if (tokens[2]) {
109 35add24a 2021-10-08 thomas if (*server_capabilities == NULL) {
110 35add24a 2021-10-08 thomas char *p;
111 35add24a 2021-10-08 thomas *server_capabilities = tokens[2];
112 35add24a 2021-10-08 thomas p = strrchr(*server_capabilities, '\n');
113 35add24a 2021-10-08 thomas if (p)
114 35add24a 2021-10-08 thomas *p = '\0';
115 35add24a 2021-10-08 thomas } else
116 35add24a 2021-10-08 thomas free(tokens[2]);
117 bd3d9e54 2021-09-05 stsp }
118 bd3d9e54 2021-09-05 stsp
119 bd3d9e54 2021-09-05 stsp return NULL;
120 bd3d9e54 2021-09-05 stsp }
121 bd3d9e54 2021-09-05 stsp
122 3efd8e31 2022-10-23 thomas const struct got_error *
123 3efd8e31 2022-10-23 thomas got_gitproto_parse_want_line(char **id_str,
124 3efd8e31 2022-10-23 thomas char **capabilities, char *line, int len)
125 3efd8e31 2022-10-23 thomas {
126 3efd8e31 2022-10-23 thomas const struct got_error *err = NULL;
127 3efd8e31 2022-10-23 thomas char *tokens[3];
128 3efd8e31 2022-10-23 thomas
129 3efd8e31 2022-10-23 thomas *id_str = NULL;
130 3efd8e31 2022-10-23 thomas /* don't reset *capabilities */
131 3efd8e31 2022-10-23 thomas
132 3efd8e31 2022-10-23 thomas err = tokenize_line(tokens, line, len, 2, nitems(tokens));
133 3efd8e31 2022-10-23 thomas if (err)
134 3efd8e31 2022-10-23 thomas return err;
135 3efd8e31 2022-10-23 thomas
136 3efd8e31 2022-10-23 thomas if (tokens[0] == NULL) {
137 3efd8e31 2022-10-23 thomas free_tokens(tokens, nitems(tokens));
138 3efd8e31 2022-10-23 thomas return got_error_msg(GOT_ERR_BAD_PACKET, "empty want-line");
139 3efd8e31 2022-10-23 thomas }
140 3efd8e31 2022-10-23 thomas
141 3efd8e31 2022-10-23 thomas if (strcmp(tokens[0], "want") != 0) {
142 3efd8e31 2022-10-23 thomas free_tokens(tokens, nitems(tokens));
143 3efd8e31 2022-10-23 thomas return got_error_msg(GOT_ERR_BAD_PACKET, "bad want-line");
144 3efd8e31 2022-10-23 thomas }
145 3efd8e31 2022-10-23 thomas
146 3efd8e31 2022-10-23 thomas free(tokens[0]);
147 3efd8e31 2022-10-23 thomas if (tokens[1])
148 3efd8e31 2022-10-23 thomas *id_str = tokens[1];
149 3efd8e31 2022-10-23 thomas if (tokens[2]) {
150 3efd8e31 2022-10-23 thomas if (*capabilities == NULL) {
151 3efd8e31 2022-10-23 thomas char *p;
152 3efd8e31 2022-10-23 thomas *capabilities = tokens[2];
153 3efd8e31 2022-10-23 thomas p = strrchr(*capabilities, '\n');
154 3efd8e31 2022-10-23 thomas if (p)
155 3efd8e31 2022-10-23 thomas *p = '\0';
156 3efd8e31 2022-10-23 thomas } else
157 3efd8e31 2022-10-23 thomas free(tokens[2]);
158 3efd8e31 2022-10-23 thomas }
159 3efd8e31 2022-10-23 thomas
160 3efd8e31 2022-10-23 thomas return NULL;
161 3efd8e31 2022-10-23 thomas }
162 3efd8e31 2022-10-23 thomas
163 3efd8e31 2022-10-23 thomas const struct got_error *
164 3efd8e31 2022-10-23 thomas got_gitproto_parse_have_line(char **id_str, char *line, int len)
165 3efd8e31 2022-10-23 thomas {
166 3efd8e31 2022-10-23 thomas const struct got_error *err = NULL;
167 3efd8e31 2022-10-23 thomas char *tokens[2];
168 3efd8e31 2022-10-23 thomas
169 3efd8e31 2022-10-23 thomas *id_str = NULL;
170 3efd8e31 2022-10-23 thomas
171 3efd8e31 2022-10-23 thomas err = tokenize_line(tokens, line, len, 2, nitems(tokens));
172 3efd8e31 2022-10-23 thomas if (err)
173 3efd8e31 2022-10-23 thomas return err;
174 3efd8e31 2022-10-23 thomas
175 3efd8e31 2022-10-23 thomas if (tokens[0] == NULL) {
176 3efd8e31 2022-10-23 thomas free_tokens(tokens, nitems(tokens));
177 3efd8e31 2022-10-23 thomas return got_error_msg(GOT_ERR_BAD_PACKET, "empty have-line");
178 3efd8e31 2022-10-23 thomas }
179 3efd8e31 2022-10-23 thomas
180 3efd8e31 2022-10-23 thomas if (strcmp(tokens[0], "have") != 0) {
181 3efd8e31 2022-10-23 thomas free_tokens(tokens, nitems(tokens));
182 3efd8e31 2022-10-23 thomas return got_error_msg(GOT_ERR_BAD_PACKET, "bad have-line");
183 3efd8e31 2022-10-23 thomas }
184 3efd8e31 2022-10-23 thomas
185 3efd8e31 2022-10-23 thomas free(tokens[0]);
186 3efd8e31 2022-10-23 thomas if (tokens[1])
187 3efd8e31 2022-10-23 thomas *id_str = tokens[1];
188 3efd8e31 2022-10-23 thomas
189 3efd8e31 2022-10-23 thomas return NULL;
190 3efd8e31 2022-10-23 thomas }
191 3efd8e31 2022-10-23 thomas
192 3efd8e31 2022-10-23 thomas const struct got_error *
193 3efd8e31 2022-10-23 thomas got_gitproto_parse_ref_update_line(char **old_id_str, char **new_id_str,
194 3efd8e31 2022-10-23 thomas char **refname, char **capabilities, char *line, size_t len)
195 3efd8e31 2022-10-23 thomas {
196 3efd8e31 2022-10-23 thomas const struct got_error *err = NULL;
197 3efd8e31 2022-10-23 thomas char *tokens[4];
198 3efd8e31 2022-10-23 thomas
199 3efd8e31 2022-10-23 thomas *old_id_str = NULL;
200 3efd8e31 2022-10-23 thomas *new_id_str = NULL;
201 3efd8e31 2022-10-23 thomas *refname = NULL;
202 3efd8e31 2022-10-23 thomas
203 3efd8e31 2022-10-23 thomas /* don't reset *capabilities */
204 3efd8e31 2022-10-23 thomas
205 3efd8e31 2022-10-23 thomas err = tokenize_line(tokens, line, len, 3, nitems(tokens));
206 3efd8e31 2022-10-23 thomas if (err)
207 3efd8e31 2022-10-23 thomas return err;
208 3efd8e31 2022-10-23 thomas
209 3efd8e31 2022-10-23 thomas if (tokens[0] == NULL || tokens[1] == NULL || tokens[2] == NULL) {
210 3efd8e31 2022-10-23 thomas free_tokens(tokens, nitems(tokens));
211 3efd8e31 2022-10-23 thomas return got_error_msg(GOT_ERR_BAD_PACKET, "empty ref-update");
212 3efd8e31 2022-10-23 thomas }
213 3efd8e31 2022-10-23 thomas
214 3efd8e31 2022-10-23 thomas *old_id_str = tokens[0];
215 3efd8e31 2022-10-23 thomas *new_id_str = tokens[1];
216 3efd8e31 2022-10-23 thomas *refname = tokens[2];
217 3efd8e31 2022-10-23 thomas if (tokens[3]) {
218 3efd8e31 2022-10-23 thomas if (*capabilities == NULL) {
219 3efd8e31 2022-10-23 thomas char *p;
220 3efd8e31 2022-10-23 thomas *capabilities = tokens[3];
221 3efd8e31 2022-10-23 thomas p = strrchr(*capabilities, '\n');
222 3efd8e31 2022-10-23 thomas if (p)
223 3efd8e31 2022-10-23 thomas *p = '\0';
224 3efd8e31 2022-10-23 thomas } else
225 3efd8e31 2022-10-23 thomas free(tokens[3]);
226 3efd8e31 2022-10-23 thomas }
227 3efd8e31 2022-10-23 thomas
228 3efd8e31 2022-10-23 thomas return NULL;
229 3efd8e31 2022-10-23 thomas }
230 3efd8e31 2022-10-23 thomas
231 bd3d9e54 2021-09-05 stsp static const struct got_error *
232 bd3d9e54 2021-09-05 stsp match_capability(char **my_capabilities, const char *capa,
233 bd3d9e54 2021-09-05 stsp const struct got_capability *mycapa)
234 bd3d9e54 2021-09-05 stsp {
235 bd3d9e54 2021-09-05 stsp char *equalsign;
236 bd3d9e54 2021-09-05 stsp char *s;
237 bd3d9e54 2021-09-05 stsp
238 bd3d9e54 2021-09-05 stsp equalsign = strchr(capa, '=');
239 bd3d9e54 2021-09-05 stsp if (equalsign) {
240 bd3d9e54 2021-09-05 stsp if (strncmp(capa, mycapa->key, equalsign - capa) != 0)
241 bd3d9e54 2021-09-05 stsp return NULL;
242 bd3d9e54 2021-09-05 stsp } else {
243 bd3d9e54 2021-09-05 stsp if (strcmp(capa, mycapa->key) != 0)
244 bd3d9e54 2021-09-05 stsp return NULL;
245 bd3d9e54 2021-09-05 stsp }
246 bd3d9e54 2021-09-05 stsp
247 bd3d9e54 2021-09-05 stsp if (asprintf(&s, "%s %s%s%s",
248 bd3d9e54 2021-09-05 stsp *my_capabilities != NULL ? *my_capabilities : "",
249 bd3d9e54 2021-09-05 stsp mycapa->key,
250 bd3d9e54 2021-09-05 stsp mycapa->value != NULL ? "=" : "",
251 e33e440b 2021-09-05 stsp mycapa->value != NULL ? mycapa->value : "") == -1)
252 bd3d9e54 2021-09-05 stsp return got_error_from_errno("asprintf");
253 bd3d9e54 2021-09-05 stsp
254 bd3d9e54 2021-09-05 stsp free(*my_capabilities);
255 bd3d9e54 2021-09-05 stsp *my_capabilities = s;
256 bd3d9e54 2021-09-05 stsp return NULL;
257 bd3d9e54 2021-09-05 stsp }
258 bd3d9e54 2021-09-05 stsp
259 bd3d9e54 2021-09-05 stsp static const struct got_error *
260 bd3d9e54 2021-09-05 stsp add_symref(struct got_pathlist_head *symrefs, char *capa)
261 bd3d9e54 2021-09-05 stsp {
262 bd3d9e54 2021-09-05 stsp const struct got_error *err = NULL;
263 bd3d9e54 2021-09-05 stsp char *colon, *name = NULL, *target = NULL;
264 bd3d9e54 2021-09-05 stsp
265 bd3d9e54 2021-09-05 stsp /* Need at least "A:B" */
266 bd3d9e54 2021-09-05 stsp if (strlen(capa) < 3)
267 bd3d9e54 2021-09-05 stsp return NULL;
268 bd3d9e54 2021-09-05 stsp
269 bd3d9e54 2021-09-05 stsp colon = strchr(capa, ':');
270 bd3d9e54 2021-09-05 stsp if (colon == NULL)
271 bd3d9e54 2021-09-05 stsp return NULL;
272 bd3d9e54 2021-09-05 stsp
273 bd3d9e54 2021-09-05 stsp *colon = '\0';
274 bd3d9e54 2021-09-05 stsp name = strdup(capa);
275 bd3d9e54 2021-09-05 stsp if (name == NULL)
276 bd3d9e54 2021-09-05 stsp return got_error_from_errno("strdup");
277 bd3d9e54 2021-09-05 stsp
278 bd3d9e54 2021-09-05 stsp target = strdup(colon + 1);
279 bd3d9e54 2021-09-05 stsp if (target == NULL) {
280 bd3d9e54 2021-09-05 stsp err = got_error_from_errno("strdup");
281 bd3d9e54 2021-09-05 stsp goto done;
282 bd3d9e54 2021-09-05 stsp }
283 bd3d9e54 2021-09-05 stsp
284 bd3d9e54 2021-09-05 stsp /* We can't validate the ref itself here. The main process will. */
285 bd3d9e54 2021-09-05 stsp err = got_pathlist_append(symrefs, name, target);
286 bd3d9e54 2021-09-05 stsp done:
287 bd3d9e54 2021-09-05 stsp if (err) {
288 bd3d9e54 2021-09-05 stsp free(name);
289 bd3d9e54 2021-09-05 stsp free(target);
290 bd3d9e54 2021-09-05 stsp }
291 bd3d9e54 2021-09-05 stsp return err;
292 bd3d9e54 2021-09-05 stsp }
293 bd3d9e54 2021-09-05 stsp
294 bd3d9e54 2021-09-05 stsp const struct got_error *
295 bd3d9e54 2021-09-05 stsp got_gitproto_match_capabilities(char **common_capabilities,
296 3efd8e31 2022-10-23 thomas struct got_pathlist_head *symrefs, char *capabilities,
297 bd3d9e54 2021-09-05 stsp const struct got_capability my_capabilities[], size_t ncapa)
298 bd3d9e54 2021-09-05 stsp {
299 bd3d9e54 2021-09-05 stsp const struct got_error *err = NULL;
300 bd3d9e54 2021-09-05 stsp char *capa, *equalsign;
301 bd3d9e54 2021-09-05 stsp size_t i;
302 bd3d9e54 2021-09-05 stsp
303 bd3d9e54 2021-09-05 stsp *common_capabilities = NULL;
304 bd3d9e54 2021-09-05 stsp do {
305 3efd8e31 2022-10-23 thomas capa = strsep(&capabilities, " ");
306 bd3d9e54 2021-09-05 stsp if (capa == NULL)
307 bd3d9e54 2021-09-05 stsp return NULL;
308 bd3d9e54 2021-09-05 stsp
309 bd3d9e54 2021-09-05 stsp equalsign = strchr(capa, '=');
310 bd3d9e54 2021-09-05 stsp if (equalsign != NULL && symrefs != NULL &&
311 bd3d9e54 2021-09-05 stsp strncmp(capa, "symref", equalsign - capa) == 0) {
312 bd3d9e54 2021-09-05 stsp err = add_symref(symrefs, equalsign + 1);
313 bd3d9e54 2021-09-05 stsp if (err)
314 bd3d9e54 2021-09-05 stsp break;
315 bd3d9e54 2021-09-05 stsp continue;
316 bd3d9e54 2021-09-05 stsp }
317 bd3d9e54 2021-09-05 stsp
318 bd3d9e54 2021-09-05 stsp for (i = 0; i < ncapa; i++) {
319 bd3d9e54 2021-09-05 stsp err = match_capability(common_capabilities,
320 bd3d9e54 2021-09-05 stsp capa, &my_capabilities[i]);
321 bd3d9e54 2021-09-05 stsp if (err)
322 bd3d9e54 2021-09-05 stsp break;
323 bd3d9e54 2021-09-05 stsp }
324 bd3d9e54 2021-09-05 stsp } while (capa);
325 bd3d9e54 2021-09-05 stsp
326 bd3d9e54 2021-09-05 stsp if (*common_capabilities == NULL) {
327 bd3d9e54 2021-09-05 stsp *common_capabilities = strdup("");
328 bd3d9e54 2021-09-05 stsp if (*common_capabilities == NULL)
329 bd3d9e54 2021-09-05 stsp err = got_error_from_errno("strdup");
330 bd3d9e54 2021-09-05 stsp }
331 bd3d9e54 2021-09-05 stsp return err;
332 bd3d9e54 2021-09-05 stsp }
333 3efd8e31 2022-10-23 thomas
334 3efd8e31 2022-10-23 thomas const struct got_error *
335 3efd8e31 2022-10-23 thomas got_gitproto_append_capabilities(size_t *capalen, char *buf, size_t offset,
336 3efd8e31 2022-10-23 thomas size_t bufsize, const struct got_capability my_capabilities[], size_t ncapa)
337 3efd8e31 2022-10-23 thomas {
338 3efd8e31 2022-10-23 thomas char *p = buf + offset;
339 3efd8e31 2022-10-23 thomas size_t i, len, remain = bufsize - offset;
340 3efd8e31 2022-10-23 thomas
341 3efd8e31 2022-10-23 thomas *capalen = 0;
342 3efd8e31 2022-10-23 thomas
343 3efd8e31 2022-10-23 thomas if (offset >= bufsize || remain < 1)
344 3efd8e31 2022-10-23 thomas return got_error(GOT_ERR_NO_SPACE);
345 3efd8e31 2022-10-23 thomas
346 3efd8e31 2022-10-23 thomas /* Capabilities are hidden behind a NUL byte. */
347 3efd8e31 2022-10-23 thomas *p = '\0';
348 3efd8e31 2022-10-23 thomas p++;
349 3efd8e31 2022-10-23 thomas remain--;
350 3efd8e31 2022-10-23 thomas *capalen += 1;
351 3efd8e31 2022-10-23 thomas
352 3efd8e31 2022-10-23 thomas for (i = 0; i < ncapa; i++) {
353 3efd8e31 2022-10-23 thomas len = strlcat(p, " ", remain);
354 3efd8e31 2022-10-23 thomas if (len >= remain)
355 3efd8e31 2022-10-23 thomas return got_error(GOT_ERR_NO_SPACE);
356 3efd8e31 2022-10-23 thomas remain -= len;
357 3efd8e31 2022-10-23 thomas *capalen += 1;
358 3efd8e31 2022-10-23 thomas
359 3efd8e31 2022-10-23 thomas len = strlcat(p, my_capabilities[i].key, remain);
360 3efd8e31 2022-10-23 thomas if (len >= remain)
361 3efd8e31 2022-10-23 thomas return got_error(GOT_ERR_NO_SPACE);
362 3efd8e31 2022-10-23 thomas remain -= len;
363 3efd8e31 2022-10-23 thomas *capalen += strlen(my_capabilities[i].key);
364 3efd8e31 2022-10-23 thomas
365 3efd8e31 2022-10-23 thomas if (my_capabilities[i].value == NULL)
366 3efd8e31 2022-10-23 thomas continue;
367 3efd8e31 2022-10-23 thomas
368 3efd8e31 2022-10-23 thomas len = strlcat(p, "=", remain);
369 3efd8e31 2022-10-23 thomas if (len >= remain)
370 3efd8e31 2022-10-23 thomas return got_error(GOT_ERR_NO_SPACE);
371 3efd8e31 2022-10-23 thomas remain -= len;
372 3efd8e31 2022-10-23 thomas *capalen += 1;
373 3efd8e31 2022-10-23 thomas
374 3efd8e31 2022-10-23 thomas len = strlcat(p, my_capabilities[i].value, remain);
375 3efd8e31 2022-10-23 thomas if (len >= remain)
376 3efd8e31 2022-10-23 thomas return got_error(GOT_ERR_NO_SPACE);
377 3efd8e31 2022-10-23 thomas remain -= len;
378 3efd8e31 2022-10-23 thomas *capalen += strlen(my_capabilities[i].value);
379 3efd8e31 2022-10-23 thomas }
380 3efd8e31 2022-10-23 thomas
381 3efd8e31 2022-10-23 thomas return NULL;
382 3efd8e31 2022-10-23 thomas }
383 3efd8e31 2022-10-23 thomas
384 3efd8e31 2022-10-23 thomas const struct got_error *
385 3efd8e31 2022-10-23 thomas got_gitproto_split_capabilities_str(struct got_capability **capabilities,
386 3efd8e31 2022-10-23 thomas size_t *ncapabilities, char *capabilities_str)
387 3efd8e31 2022-10-23 thomas {
388 3efd8e31 2022-10-23 thomas char *capastr, *capa;
389 3efd8e31 2022-10-23 thomas size_t i;
390 3efd8e31 2022-10-23 thomas
391 3efd8e31 2022-10-23 thomas *capabilities = NULL;
392 3efd8e31 2022-10-23 thomas *ncapabilities = 0;
393 3efd8e31 2022-10-23 thomas
394 3efd8e31 2022-10-23 thomas /* Compute number of capabilities on a copy of the input string. */
395 3efd8e31 2022-10-23 thomas capastr = strdup(capabilities_str);
396 3efd8e31 2022-10-23 thomas if (capastr == NULL)
397 3efd8e31 2022-10-23 thomas return got_error_from_errno("strdup");
398 3efd8e31 2022-10-23 thomas do {
399 3efd8e31 2022-10-23 thomas capa = strsep(&capastr, " ");
400 3efd8e31 2022-10-23 thomas if (capa && *capa != '\0')
401 3efd8e31 2022-10-23 thomas (*ncapabilities)++;
402 3efd8e31 2022-10-23 thomas } while (capa);
403 3efd8e31 2022-10-23 thomas free(capastr);
404 3efd8e31 2022-10-23 thomas
405 3efd8e31 2022-10-23 thomas *capabilities = calloc(*ncapabilities, sizeof(**capabilities));
406 3efd8e31 2022-10-23 thomas if (*capabilities == NULL)
407 3efd8e31 2022-10-23 thomas return got_error_from_errno("calloc");
408 3efd8e31 2022-10-23 thomas
409 3efd8e31 2022-10-23 thomas /* Modify input string in place, splitting it into key/value tuples. */
410 3efd8e31 2022-10-23 thomas i = 0;
411 3efd8e31 2022-10-23 thomas for (;;) {
412 3efd8e31 2022-10-23 thomas char *key = NULL, *value = NULL, *equalsign;
413 3efd8e31 2022-10-23 thomas
414 3efd8e31 2022-10-23 thomas capa = strsep(&capabilities_str, " ");
415 3efd8e31 2022-10-23 thomas if (capa == NULL)
416 3efd8e31 2022-10-23 thomas break;
417 3efd8e31 2022-10-23 thomas if (*capa == '\0')
418 3efd8e31 2022-10-23 thomas continue;
419 3efd8e31 2022-10-23 thomas
420 3efd8e31 2022-10-23 thomas if (i >= *ncapabilities) { /* should not happen */
421 3efd8e31 2022-10-23 thomas free(*capabilities);
422 3efd8e31 2022-10-23 thomas *capabilities = NULL;
423 3efd8e31 2022-10-23 thomas *ncapabilities = 0;
424 3efd8e31 2022-10-23 thomas return got_error(GOT_ERR_NO_SPACE);
425 3efd8e31 2022-10-23 thomas }
426 3efd8e31 2022-10-23 thomas
427 3efd8e31 2022-10-23 thomas key = capa;
428 3efd8e31 2022-10-23 thomas
429 3efd8e31 2022-10-23 thomas equalsign = strchr(capa, '=');
430 3efd8e31 2022-10-23 thomas if (equalsign != NULL) {
431 3efd8e31 2022-10-23 thomas *equalsign = '\0';
432 3efd8e31 2022-10-23 thomas value = equalsign + 1;
433 3efd8e31 2022-10-23 thomas }
434 3efd8e31 2022-10-23 thomas
435 3efd8e31 2022-10-23 thomas (*capabilities)[i].key = key;
436 3efd8e31 2022-10-23 thomas (*capabilities)[i].value = value;
437 3efd8e31 2022-10-23 thomas i++;
438 3efd8e31 2022-10-23 thomas }
439 3efd8e31 2022-10-23 thomas
440 3efd8e31 2022-10-23 thomas return NULL;
441 3efd8e31 2022-10-23 thomas }