2 * Copyright (c) 2019 Ori Bernstein <ori@openbsd.org>
3 * Copyright (c) 2021 Stefan Sperling <stsp@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <sys/types.h>
25 #include "got_error.h"
28 #include "got_lib_gitproto.h"
31 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
34 static const struct got_error
*
35 tokenize_refline(char **tokens
, char *line
, int len
, int maxtokens
)
37 const struct got_error
*err
= NULL
;
41 for (i
= 0; i
< maxtokens
; i
++)
44 for (i
= 0; n
< len
&& i
< maxtokens
; i
++) {
45 while (isspace(*line
)) {
50 while (*line
!= '\0' && n
< len
&&
51 (!isspace(*line
) || i
== maxtokens
- 1)) {
55 tokens
[i
] = strndup(p
, line
- p
);
56 if (tokens
[i
] == NULL
) {
57 err
= got_error_from_errno("strndup");
60 /* Skip \0 field-delimiter at end of token. */
61 while (line
[0] == '\0' && n
< len
) {
67 err
= got_error(GOT_ERR_BAD_PACKET
);
71 for (j
= 0; j
< i
; j
++) {
79 const struct got_error
*
80 got_gitproto_parse_refline(char **id_str
, char **refname
,
81 char **server_capabilities
, char *line
, int len
)
83 const struct got_error
*err
= NULL
;
86 err
= tokenize_refline(tokens
, line
, len
, nitems(tokens
));
96 *server_capabilities
= tokens
[2];
97 p
= strrchr(*server_capabilities
, '\n');
105 static const struct got_error
*
106 match_capability(char **my_capabilities
, const char *capa
,
107 const struct got_capability
*mycapa
)
112 equalsign
= strchr(capa
, '=');
114 if (strncmp(capa
, mycapa
->key
, equalsign
- capa
) != 0)
117 if (strcmp(capa
, mycapa
->key
) != 0)
121 if (asprintf(&s
, "%s %s%s%s",
122 *my_capabilities
!= NULL
? *my_capabilities
: "",
124 mycapa
->value
!= NULL
? "=" : "",
125 mycapa
->value
!= NULL
? mycapa
->value
: "") == -1)
126 return got_error_from_errno("asprintf");
128 free(*my_capabilities
);
129 *my_capabilities
= s
;
133 static const struct got_error
*
134 add_symref(struct got_pathlist_head
*symrefs
, char *capa
)
136 const struct got_error
*err
= NULL
;
137 char *colon
, *name
= NULL
, *target
= NULL
;
139 /* Need at least "A:B" */
140 if (strlen(capa
) < 3)
143 colon
= strchr(capa
, ':');
150 return got_error_from_errno("strdup");
152 target
= strdup(colon
+ 1);
153 if (target
== NULL
) {
154 err
= got_error_from_errno("strdup");
158 /* We can't validate the ref itself here. The main process will. */
159 err
= got_pathlist_append(symrefs
, name
, target
);
168 const struct got_error
*
169 got_gitproto_match_capabilities(char **common_capabilities
,
170 struct got_pathlist_head
*symrefs
, char *server_capabilities
,
171 const struct got_capability my_capabilities
[], size_t ncapa
)
173 const struct got_error
*err
= NULL
;
174 char *capa
, *equalsign
;
177 *common_capabilities
= NULL
;
179 capa
= strsep(&server_capabilities
, " ");
183 equalsign
= strchr(capa
, '=');
184 if (equalsign
!= NULL
&& symrefs
!= NULL
&&
185 strncmp(capa
, "symref", equalsign
- capa
) == 0) {
186 err
= add_symref(symrefs
, equalsign
+ 1);
192 for (i
= 0; i
< ncapa
; i
++) {
193 err
= match_capability(common_capabilities
,
194 capa
, &my_capabilities
[i
]);
200 if (*common_capabilities
== NULL
) {
201 *common_capabilities
= strdup("");
202 if (*common_capabilities
== NULL
)
203 err
= got_error_from_errno("strdup");