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