Blame


1 56324ebe 2022-07-14 thomas /*
2 56324ebe 2022-07-14 thomas * Copyright (c) 2020-2022 Tracey Emery <tracey@traceyemery.net>
3 56324ebe 2022-07-14 thomas * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org>
4 56324ebe 2022-07-14 thomas *
5 56324ebe 2022-07-14 thomas * Permission to use, copy, modify, and distribute this software for any
6 56324ebe 2022-07-14 thomas * purpose with or without fee is hereby granted, provided that the above
7 56324ebe 2022-07-14 thomas * copyright notice and this permission notice appear in all copies.
8 56324ebe 2022-07-14 thomas *
9 56324ebe 2022-07-14 thomas * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 56324ebe 2022-07-14 thomas * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 56324ebe 2022-07-14 thomas * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 56324ebe 2022-07-14 thomas * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 56324ebe 2022-07-14 thomas * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 56324ebe 2022-07-14 thomas * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 56324ebe 2022-07-14 thomas * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 56324ebe 2022-07-14 thomas */
17 56324ebe 2022-07-14 thomas
18 56324ebe 2022-07-14 thomas #include <sys/socket.h>
19 56324ebe 2022-07-14 thomas #include <sys/stat.h>
20 56324ebe 2022-07-14 thomas
21 56324ebe 2022-07-14 thomas #include <event.h>
22 56324ebe 2022-07-14 thomas #include <stdlib.h>
23 56324ebe 2022-07-14 thomas #include <stdio.h>
24 56324ebe 2022-07-14 thomas #include <string.h>
25 56324ebe 2022-07-14 thomas #include <unistd.h>
26 56324ebe 2022-07-14 thomas
27 56324ebe 2022-07-14 thomas #include "got_error.h"
28 56324ebe 2022-07-14 thomas #include "got_object.h"
29 56324ebe 2022-07-14 thomas #include "got_reference.h"
30 56324ebe 2022-07-14 thomas #include "got_repository.h"
31 56324ebe 2022-07-14 thomas #include "got_path.h"
32 56324ebe 2022-07-14 thomas #include "got_cancel.h"
33 56324ebe 2022-07-14 thomas #include "got_diff.h"
34 56324ebe 2022-07-14 thomas #include "got_commit_graph.h"
35 56324ebe 2022-07-14 thomas #include "got_blame.h"
36 56324ebe 2022-07-14 thomas #include "got_privsep.h"
37 d7cad54e 2022-07-14 thomas
38 d7cad54e 2022-07-14 thomas #include "got_compat.h"
39 56324ebe 2022-07-14 thomas
40 56324ebe 2022-07-14 thomas #include "proc.h"
41 56324ebe 2022-07-14 thomas #include "gotwebd.h"
42 56324ebe 2022-07-14 thomas
43 56324ebe 2022-07-14 thomas static const struct got_error *got_init_repo_commit(struct repo_commit **);
44 56324ebe 2022-07-14 thomas static const struct got_error *got_init_repo_tag(struct repo_tag **);
45 56324ebe 2022-07-14 thomas static const struct got_error *got_get_repo_commit(struct request *,
46 56324ebe 2022-07-14 thomas struct repo_commit *, struct got_commit_object *, struct got_reflist_head *,
47 56324ebe 2022-07-14 thomas struct got_object_id *);
48 56324ebe 2022-07-14 thomas static const struct got_error *got_gotweb_dupfd(int *, int *);
49 56324ebe 2022-07-14 thomas static const struct got_error *got_gotweb_openfile(FILE **, int *, int *);
50 56324ebe 2022-07-14 thomas static const struct got_error *got_gotweb_flushfile(FILE *, int);
51 56324ebe 2022-07-14 thomas static const struct got_error *got_gotweb_blame_cb(void *, int, int,
52 56324ebe 2022-07-14 thomas struct got_commit_object *,struct got_object_id *);
53 56324ebe 2022-07-14 thomas
54 56324ebe 2022-07-14 thomas static int
55 56324ebe 2022-07-14 thomas isbinary(const uint8_t *buf, size_t n)
56 56324ebe 2022-07-14 thomas {
57 56324ebe 2022-07-14 thomas size_t i;
58 56324ebe 2022-07-14 thomas
59 56324ebe 2022-07-14 thomas for (i = 0; i < n; i++)
60 56324ebe 2022-07-14 thomas if (buf[i] == 0)
61 56324ebe 2022-07-14 thomas return 1;
62 56324ebe 2022-07-14 thomas return 0;
63 56324ebe 2022-07-14 thomas }
64 56324ebe 2022-07-14 thomas
65 56324ebe 2022-07-14 thomas
66 56324ebe 2022-07-14 thomas static const struct got_error *
67 56324ebe 2022-07-14 thomas got_gotweb_flushfile(FILE *f, int fd)
68 56324ebe 2022-07-14 thomas {
69 56324ebe 2022-07-14 thomas if (fseek(f, 0, SEEK_SET) == -1)
70 56324ebe 2022-07-14 thomas return got_error_from_errno("fseek");
71 56324ebe 2022-07-14 thomas
72 56324ebe 2022-07-14 thomas if (ftruncate(fd, 0) == -1)
73 56324ebe 2022-07-14 thomas return got_error_from_errno("ftruncate");
74 56324ebe 2022-07-14 thomas
75 56324ebe 2022-07-14 thomas if (fsync(fd) == -1)
76 56324ebe 2022-07-14 thomas return got_error_from_errno("fsync");
77 56324ebe 2022-07-14 thomas
78 56324ebe 2022-07-14 thomas if (f && fclose(f) == EOF)
79 56324ebe 2022-07-14 thomas return got_error_from_errno("fclose");
80 56324ebe 2022-07-14 thomas
81 56324ebe 2022-07-14 thomas if (fd != -1 && close(fd) != -1)
82 56324ebe 2022-07-14 thomas return got_error_from_errno("close");
83 56324ebe 2022-07-14 thomas
84 56324ebe 2022-07-14 thomas return NULL;
85 56324ebe 2022-07-14 thomas }
86 56324ebe 2022-07-14 thomas
87 56324ebe 2022-07-14 thomas static const struct got_error *
88 56324ebe 2022-07-14 thomas got_gotweb_openfile(FILE **f, int *priv_fd, int *fd)
89 56324ebe 2022-07-14 thomas {
90 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
91 56324ebe 2022-07-14 thomas
92 56324ebe 2022-07-14 thomas *fd = dup(*priv_fd);
93 56324ebe 2022-07-14 thomas
94 56324ebe 2022-07-14 thomas if (*fd < 0)
95 56324ebe 2022-07-14 thomas return NULL;
96 56324ebe 2022-07-14 thomas
97 56324ebe 2022-07-14 thomas *f = fdopen(*fd, "w+");
98 56324ebe 2022-07-14 thomas if (*f == NULL) {
99 56324ebe 2022-07-14 thomas close(*fd);
100 56324ebe 2022-07-14 thomas error = got_error(GOT_ERR_PRIVSEP_NO_FD);
101 56324ebe 2022-07-14 thomas }
102 56324ebe 2022-07-14 thomas
103 56324ebe 2022-07-14 thomas return error;
104 56324ebe 2022-07-14 thomas }
105 56324ebe 2022-07-14 thomas
106 56324ebe 2022-07-14 thomas static const struct got_error *
107 56324ebe 2022-07-14 thomas got_gotweb_dupfd(int *priv_fd, int *fd)
108 56324ebe 2022-07-14 thomas {
109 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
110 56324ebe 2022-07-14 thomas
111 56324ebe 2022-07-14 thomas *fd = dup(*priv_fd);
112 56324ebe 2022-07-14 thomas
113 56324ebe 2022-07-14 thomas if (*fd < 0)
114 56324ebe 2022-07-14 thomas return NULL;
115 56324ebe 2022-07-14 thomas
116 56324ebe 2022-07-14 thomas return error;
117 56324ebe 2022-07-14 thomas }
118 56324ebe 2022-07-14 thomas
119 56324ebe 2022-07-14 thomas const struct got_error *
120 56324ebe 2022-07-14 thomas got_get_repo_owner(char **owner, struct request *c, char *dir)
121 56324ebe 2022-07-14 thomas {
122 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
123 56324ebe 2022-07-14 thomas struct server *srv = c->srv;
124 56324ebe 2022-07-14 thomas struct transport *t = c->t;
125 56324ebe 2022-07-14 thomas struct got_repository *repo = t->repo;
126 56324ebe 2022-07-14 thomas const char *gitconfig_owner;
127 56324ebe 2022-07-14 thomas
128 56324ebe 2022-07-14 thomas *owner = NULL;
129 56324ebe 2022-07-14 thomas
130 56324ebe 2022-07-14 thomas if (srv->show_repo_owner == 0)
131 56324ebe 2022-07-14 thomas return NULL;
132 56324ebe 2022-07-14 thomas
133 56324ebe 2022-07-14 thomas gitconfig_owner = got_repo_get_gitconfig_owner(repo);
134 56324ebe 2022-07-14 thomas if (gitconfig_owner) {
135 56324ebe 2022-07-14 thomas *owner = strdup(gitconfig_owner);
136 56324ebe 2022-07-14 thomas if (*owner == NULL)
137 56324ebe 2022-07-14 thomas return got_error_from_errno("strdup");
138 56324ebe 2022-07-14 thomas }
139 56324ebe 2022-07-14 thomas return error;
140 56324ebe 2022-07-14 thomas }
141 56324ebe 2022-07-14 thomas
142 56324ebe 2022-07-14 thomas const struct got_error *
143 56324ebe 2022-07-14 thomas got_get_repo_age(char **repo_age, struct request *c, char *dir,
144 56324ebe 2022-07-14 thomas const char *refname, int ref_tm)
145 56324ebe 2022-07-14 thomas {
146 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
147 56324ebe 2022-07-14 thomas struct server *srv = c->srv;
148 56324ebe 2022-07-14 thomas struct transport *t = c->t;
149 56324ebe 2022-07-14 thomas struct got_repository *repo = t->repo;
150 56324ebe 2022-07-14 thomas struct got_commit_object *commit = NULL;
151 56324ebe 2022-07-14 thomas struct got_reflist_head refs;
152 56324ebe 2022-07-14 thomas struct got_reflist_entry *re;
153 56324ebe 2022-07-14 thomas time_t committer_time = 0, cmp_time = 0;
154 56324ebe 2022-07-14 thomas
155 56324ebe 2022-07-14 thomas *repo_age = NULL;
156 56324ebe 2022-07-14 thomas TAILQ_INIT(&refs);
157 56324ebe 2022-07-14 thomas
158 56324ebe 2022-07-14 thomas if (srv->show_repo_age == 0)
159 56324ebe 2022-07-14 thomas return NULL;
160 56324ebe 2022-07-14 thomas
161 56324ebe 2022-07-14 thomas error = got_ref_list(&refs, repo, "refs/heads",
162 56324ebe 2022-07-14 thomas got_ref_cmp_by_name, NULL);
163 56324ebe 2022-07-14 thomas if (error)
164 56324ebe 2022-07-14 thomas goto done;
165 56324ebe 2022-07-14 thomas
166 56324ebe 2022-07-14 thomas /*
167 56324ebe 2022-07-14 thomas * Find the youngest branch tip in the repository, or the age of
168 56324ebe 2022-07-14 thomas * the a specific branch tip if a name was provided by the caller.
169 56324ebe 2022-07-14 thomas */
170 56324ebe 2022-07-14 thomas TAILQ_FOREACH(re, &refs, entry) {
171 56324ebe 2022-07-14 thomas struct got_object_id *id = NULL;
172 56324ebe 2022-07-14 thomas
173 56324ebe 2022-07-14 thomas if (refname && strcmp(got_ref_get_name(re->ref), refname) != 0)
174 56324ebe 2022-07-14 thomas continue;
175 56324ebe 2022-07-14 thomas
176 56324ebe 2022-07-14 thomas error = got_ref_resolve(&id, repo, re->ref);
177 56324ebe 2022-07-14 thomas if (error)
178 56324ebe 2022-07-14 thomas goto done;
179 56324ebe 2022-07-14 thomas
180 56324ebe 2022-07-14 thomas error = got_object_open_as_commit(&commit, repo, id);
181 56324ebe 2022-07-14 thomas free(id);
182 56324ebe 2022-07-14 thomas if (error)
183 56324ebe 2022-07-14 thomas goto done;
184 56324ebe 2022-07-14 thomas
185 56324ebe 2022-07-14 thomas committer_time =
186 56324ebe 2022-07-14 thomas got_object_commit_get_committer_time(commit);
187 56324ebe 2022-07-14 thomas got_object_commit_close(commit);
188 56324ebe 2022-07-14 thomas if (cmp_time < committer_time)
189 56324ebe 2022-07-14 thomas cmp_time = committer_time;
190 56324ebe 2022-07-14 thomas
191 56324ebe 2022-07-14 thomas if (refname)
192 56324ebe 2022-07-14 thomas break;
193 56324ebe 2022-07-14 thomas }
194 56324ebe 2022-07-14 thomas
195 56324ebe 2022-07-14 thomas if (cmp_time != 0) {
196 56324ebe 2022-07-14 thomas committer_time = cmp_time;
197 56324ebe 2022-07-14 thomas error = gotweb_get_time_str(repo_age, committer_time, ref_tm);
198 56324ebe 2022-07-14 thomas }
199 56324ebe 2022-07-14 thomas done:
200 56324ebe 2022-07-14 thomas got_ref_list_free(&refs);
201 56324ebe 2022-07-14 thomas return error;
202 56324ebe 2022-07-14 thomas }
203 56324ebe 2022-07-14 thomas
204 56324ebe 2022-07-14 thomas static const struct got_error *
205 56324ebe 2022-07-14 thomas got_get_repo_commit(struct request *c, struct repo_commit *repo_commit,
206 56324ebe 2022-07-14 thomas struct got_commit_object *commit, struct got_reflist_head *refs,
207 56324ebe 2022-07-14 thomas struct got_object_id *id)
208 56324ebe 2022-07-14 thomas {
209 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
210 56324ebe 2022-07-14 thomas struct got_reflist_entry *re;
211 56324ebe 2022-07-14 thomas struct got_object_id *id2 = NULL;
212 56324ebe 2022-07-14 thomas struct got_object_qid *parent_id;
213 56324ebe 2022-07-14 thomas struct transport *t = c->t;
214 56324ebe 2022-07-14 thomas struct querystring *qs = c->t->qs;
215 56324ebe 2022-07-14 thomas char *commit_msg = NULL, *commit_msg0;
216 56324ebe 2022-07-14 thomas
217 56324ebe 2022-07-14 thomas TAILQ_FOREACH(re, refs, entry) {
218 56324ebe 2022-07-14 thomas char *s;
219 56324ebe 2022-07-14 thomas const char *name;
220 56324ebe 2022-07-14 thomas struct got_tag_object *tag = NULL;
221 56324ebe 2022-07-14 thomas struct got_object_id *ref_id;
222 56324ebe 2022-07-14 thomas int cmp;
223 56324ebe 2022-07-14 thomas
224 56324ebe 2022-07-14 thomas if (got_ref_is_symbolic(re->ref))
225 56324ebe 2022-07-14 thomas continue;
226 56324ebe 2022-07-14 thomas
227 56324ebe 2022-07-14 thomas name = got_ref_get_name(re->ref);
228 56324ebe 2022-07-14 thomas if (strncmp(name, "refs/", 5) == 0)
229 56324ebe 2022-07-14 thomas name += 5;
230 56324ebe 2022-07-14 thomas if (strncmp(name, "got/", 4) == 0)
231 56324ebe 2022-07-14 thomas continue;
232 56324ebe 2022-07-14 thomas if (strncmp(name, "heads/", 6) == 0)
233 56324ebe 2022-07-14 thomas name += 6;
234 56324ebe 2022-07-14 thomas if (strncmp(name, "remotes/", 8) == 0) {
235 56324ebe 2022-07-14 thomas name += 8;
236 56324ebe 2022-07-14 thomas s = strstr(name, "/" GOT_REF_HEAD);
237 56324ebe 2022-07-14 thomas if (s != NULL && s[strlen(s)] == '\0')
238 56324ebe 2022-07-14 thomas continue;
239 56324ebe 2022-07-14 thomas }
240 56324ebe 2022-07-14 thomas error = got_ref_resolve(&ref_id, t->repo, re->ref);
241 56324ebe 2022-07-14 thomas if (error)
242 56324ebe 2022-07-14 thomas return error;
243 56324ebe 2022-07-14 thomas if (strncmp(name, "tags/", 5) == 0) {
244 56324ebe 2022-07-14 thomas error = got_object_open_as_tag(&tag, t->repo, ref_id);
245 56324ebe 2022-07-14 thomas if (error) {
246 56324ebe 2022-07-14 thomas if (error->code != GOT_ERR_OBJ_TYPE) {
247 56324ebe 2022-07-14 thomas free(ref_id);
248 56324ebe 2022-07-14 thomas continue;
249 56324ebe 2022-07-14 thomas }
250 56324ebe 2022-07-14 thomas /*
251 56324ebe 2022-07-14 thomas * Ref points at something other
252 56324ebe 2022-07-14 thomas * than a tag.
253 56324ebe 2022-07-14 thomas */
254 56324ebe 2022-07-14 thomas error = NULL;
255 56324ebe 2022-07-14 thomas tag = NULL;
256 56324ebe 2022-07-14 thomas }
257 56324ebe 2022-07-14 thomas }
258 56324ebe 2022-07-14 thomas cmp = got_object_id_cmp(tag ?
259 56324ebe 2022-07-14 thomas got_object_tag_get_object_id(tag) : ref_id, id);
260 56324ebe 2022-07-14 thomas free(ref_id);
261 56324ebe 2022-07-14 thomas if (tag)
262 56324ebe 2022-07-14 thomas got_object_tag_close(tag);
263 56324ebe 2022-07-14 thomas if (cmp != 0)
264 56324ebe 2022-07-14 thomas continue;
265 56324ebe 2022-07-14 thomas s = repo_commit->refs_str;
266 56324ebe 2022-07-14 thomas if (asprintf(&repo_commit->refs_str, "%s%s%s", s ? s : "",
267 56324ebe 2022-07-14 thomas s ? ", " : "", name) == -1) {
268 56324ebe 2022-07-14 thomas error = got_error_from_errno("asprintf");
269 56324ebe 2022-07-14 thomas free(s);
270 56324ebe 2022-07-14 thomas repo_commit->refs_str = NULL;
271 56324ebe 2022-07-14 thomas return error;
272 56324ebe 2022-07-14 thomas }
273 56324ebe 2022-07-14 thomas free(s);
274 56324ebe 2022-07-14 thomas }
275 56324ebe 2022-07-14 thomas
276 56324ebe 2022-07-14 thomas error = got_object_id_str(&repo_commit->commit_id, id);
277 56324ebe 2022-07-14 thomas if (error)
278 56324ebe 2022-07-14 thomas return error;
279 56324ebe 2022-07-14 thomas
280 56324ebe 2022-07-14 thomas error = got_object_id_str(&repo_commit->tree_id,
281 56324ebe 2022-07-14 thomas got_object_commit_get_tree_id(commit));
282 56324ebe 2022-07-14 thomas if (error)
283 56324ebe 2022-07-14 thomas return error;
284 56324ebe 2022-07-14 thomas
285 56324ebe 2022-07-14 thomas if (qs->action == DIFF) {
286 56324ebe 2022-07-14 thomas parent_id = STAILQ_FIRST(
287 56324ebe 2022-07-14 thomas got_object_commit_get_parent_ids(commit));
288 56324ebe 2022-07-14 thomas if (parent_id != NULL) {
289 56324ebe 2022-07-14 thomas id2 = got_object_id_dup(&parent_id->id);
290 56324ebe 2022-07-14 thomas error = got_object_id_str(&repo_commit->parent_id, id2);
291 56324ebe 2022-07-14 thomas if (error)
292 56324ebe 2022-07-14 thomas return error;
293 56324ebe 2022-07-14 thomas free(id2);
294 56324ebe 2022-07-14 thomas } else {
295 56324ebe 2022-07-14 thomas repo_commit->parent_id = strdup("/dev/null");
296 56324ebe 2022-07-14 thomas if (repo_commit->parent_id == NULL) {
297 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
298 56324ebe 2022-07-14 thomas return error;
299 56324ebe 2022-07-14 thomas }
300 56324ebe 2022-07-14 thomas }
301 56324ebe 2022-07-14 thomas }
302 56324ebe 2022-07-14 thomas
303 56324ebe 2022-07-14 thomas repo_commit->committer_time =
304 56324ebe 2022-07-14 thomas got_object_commit_get_committer_time(commit);
305 56324ebe 2022-07-14 thomas
306 56324ebe 2022-07-14 thomas repo_commit->author =
307 56324ebe 2022-07-14 thomas strdup(got_object_commit_get_author(commit));
308 56324ebe 2022-07-14 thomas if (repo_commit->author == NULL) {
309 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
310 56324ebe 2022-07-14 thomas return error;
311 56324ebe 2022-07-14 thomas }
312 56324ebe 2022-07-14 thomas repo_commit->committer =
313 56324ebe 2022-07-14 thomas strdup(got_object_commit_get_committer(commit));
314 56324ebe 2022-07-14 thomas if (repo_commit->committer == NULL) {
315 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
316 56324ebe 2022-07-14 thomas return error;
317 56324ebe 2022-07-14 thomas }
318 56324ebe 2022-07-14 thomas error = got_object_commit_get_logmsg(&commit_msg0, commit);
319 56324ebe 2022-07-14 thomas if (error)
320 56324ebe 2022-07-14 thomas return error;
321 56324ebe 2022-07-14 thomas
322 56324ebe 2022-07-14 thomas commit_msg = commit_msg0;
323 56324ebe 2022-07-14 thomas while (*commit_msg == '\n')
324 56324ebe 2022-07-14 thomas commit_msg++;
325 56324ebe 2022-07-14 thomas
326 56324ebe 2022-07-14 thomas repo_commit->commit_msg = strdup(commit_msg);
327 56324ebe 2022-07-14 thomas if (repo_commit->commit_msg == NULL)
328 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
329 56324ebe 2022-07-14 thomas free(commit_msg0);
330 56324ebe 2022-07-14 thomas return error;
331 56324ebe 2022-07-14 thomas }
332 56324ebe 2022-07-14 thomas
333 56324ebe 2022-07-14 thomas const struct got_error *
334 56324ebe 2022-07-14 thomas got_get_repo_commits(struct request *c, int limit)
335 56324ebe 2022-07-14 thomas {
336 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
337 56324ebe 2022-07-14 thomas struct got_object_id *id = NULL;
338 56324ebe 2022-07-14 thomas struct got_commit_graph *graph = NULL;
339 56324ebe 2022-07-14 thomas struct got_commit_object *commit = NULL;
340 56324ebe 2022-07-14 thomas struct got_reflist_head refs;
341 56324ebe 2022-07-14 thomas struct got_reference *ref;
342 56324ebe 2022-07-14 thomas struct repo_commit *repo_commit = NULL;
343 56324ebe 2022-07-14 thomas struct server *srv = c->srv;
344 56324ebe 2022-07-14 thomas struct transport *t = c->t;
345 56324ebe 2022-07-14 thomas struct got_repository *repo = t->repo;
346 56324ebe 2022-07-14 thomas struct querystring *qs = t->qs;
347 56324ebe 2022-07-14 thomas struct repo_dir *repo_dir = t->repo_dir;
348 56324ebe 2022-07-14 thomas char *in_repo_path = NULL, *repo_path = NULL, *file_path = NULL;
349 56324ebe 2022-07-14 thomas int chk_next = 0, chk_multi = 0, commit_found = 0;
350 56324ebe 2022-07-14 thomas int obj_type, limit_chk = 0;
351 56324ebe 2022-07-14 thomas
352 56324ebe 2022-07-14 thomas TAILQ_INIT(&refs);
353 56324ebe 2022-07-14 thomas
354 56324ebe 2022-07-14 thomas if (qs->file != NULL && strlen(qs->file) > 0)
355 56324ebe 2022-07-14 thomas if (asprintf(&file_path, "%s/%s", qs->folder ? qs->folder : "",
356 56324ebe 2022-07-14 thomas qs->file) == -1)
357 56324ebe 2022-07-14 thomas return got_error_from_errno("asprintf");
358 56324ebe 2022-07-14 thomas
359 56324ebe 2022-07-14 thomas if (asprintf(&repo_path, "%s/%s", srv->repos_path,
360 56324ebe 2022-07-14 thomas repo_dir->name) == -1)
361 56324ebe 2022-07-14 thomas return got_error_from_errno("asprintf");
362 56324ebe 2022-07-14 thomas
363 56324ebe 2022-07-14 thomas error = got_init_repo_commit(&repo_commit);
364 56324ebe 2022-07-14 thomas if (error)
365 56324ebe 2022-07-14 thomas return error;
366 56324ebe 2022-07-14 thomas
367 56324ebe 2022-07-14 thomas /*
368 56324ebe 2022-07-14 thomas * XXX: jumping directly to a commit id via
369 56324ebe 2022-07-14 thomas * got_repo_match_object_id_prefix significantly improves performance,
370 56324ebe 2022-07-14 thomas * but does not allow us to create a PREVIOUS button, since commits can
371 56324ebe 2022-07-14 thomas * only be itereated forward. So, we have to match as we iterate from
372 56324ebe 2022-07-14 thomas * the headref.
373 56324ebe 2022-07-14 thomas */
374 56324ebe 2022-07-14 thomas if (qs->action == BRIEFS || qs->action == COMMITS ||
375 56324ebe 2022-07-14 thomas (qs->action == TREE && qs->commit == NULL)) {
376 56324ebe 2022-07-14 thomas error = got_ref_open(&ref, repo, qs->headref, 0);
377 56324ebe 2022-07-14 thomas if (error)
378 56324ebe 2022-07-14 thomas goto done;
379 56324ebe 2022-07-14 thomas
380 56324ebe 2022-07-14 thomas error = got_ref_resolve(&id, repo, ref);
381 56324ebe 2022-07-14 thomas got_ref_close(ref);
382 56324ebe 2022-07-14 thomas if (error)
383 56324ebe 2022-07-14 thomas goto done;
384 56324ebe 2022-07-14 thomas } else if (qs->commit != NULL) {
385 56324ebe 2022-07-14 thomas error = got_ref_open(&ref, repo, qs->commit, 0);
386 56324ebe 2022-07-14 thomas if (error == NULL) {
387 56324ebe 2022-07-14 thomas error = got_ref_resolve(&id, repo, ref);
388 56324ebe 2022-07-14 thomas if (error)
389 56324ebe 2022-07-14 thomas goto done;
390 56324ebe 2022-07-14 thomas error = got_object_get_type(&obj_type, repo, id);
391 56324ebe 2022-07-14 thomas got_ref_close(ref);
392 56324ebe 2022-07-14 thomas if (error)
393 56324ebe 2022-07-14 thomas goto done;
394 56324ebe 2022-07-14 thomas if (obj_type == GOT_OBJ_TYPE_TAG) {
395 56324ebe 2022-07-14 thomas struct got_tag_object *tag;
396 56324ebe 2022-07-14 thomas error = got_object_open_as_tag(&tag, repo, id);
397 56324ebe 2022-07-14 thomas if (error)
398 56324ebe 2022-07-14 thomas goto done;
399 56324ebe 2022-07-14 thomas if (got_object_tag_get_object_type(tag) !=
400 56324ebe 2022-07-14 thomas GOT_OBJ_TYPE_COMMIT) {
401 56324ebe 2022-07-14 thomas got_object_tag_close(tag);
402 56324ebe 2022-07-14 thomas error = got_error(GOT_ERR_OBJ_TYPE);
403 56324ebe 2022-07-14 thomas goto done;
404 56324ebe 2022-07-14 thomas }
405 56324ebe 2022-07-14 thomas free(id);
406 56324ebe 2022-07-14 thomas id = got_object_id_dup(
407 56324ebe 2022-07-14 thomas got_object_tag_get_object_id(tag));
408 56324ebe 2022-07-14 thomas if (id == NULL)
409 56324ebe 2022-07-14 thomas error = got_error_from_errno(
410 56324ebe 2022-07-14 thomas "got_object_id_dup");
411 56324ebe 2022-07-14 thomas got_object_tag_close(tag);
412 56324ebe 2022-07-14 thomas if (error)
413 56324ebe 2022-07-14 thomas goto done;
414 56324ebe 2022-07-14 thomas } else if (obj_type != GOT_OBJ_TYPE_COMMIT) {
415 56324ebe 2022-07-14 thomas error = got_error(GOT_ERR_OBJ_TYPE);
416 56324ebe 2022-07-14 thomas goto done;
417 56324ebe 2022-07-14 thomas }
418 56324ebe 2022-07-14 thomas }
419 56324ebe 2022-07-14 thomas error = got_repo_match_object_id_prefix(&id, qs->commit,
420 56324ebe 2022-07-14 thomas GOT_OBJ_TYPE_COMMIT, repo);
421 56324ebe 2022-07-14 thomas if (error)
422 56324ebe 2022-07-14 thomas goto done;
423 56324ebe 2022-07-14 thomas }
424 56324ebe 2022-07-14 thomas
425 56324ebe 2022-07-14 thomas error = got_repo_map_path(&in_repo_path, repo, repo_path);
426 56324ebe 2022-07-14 thomas if (error)
427 56324ebe 2022-07-14 thomas goto done;
428 56324ebe 2022-07-14 thomas
429 56324ebe 2022-07-14 thomas error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
430 56324ebe 2022-07-14 thomas if (error)
431 56324ebe 2022-07-14 thomas goto done;
432 56324ebe 2022-07-14 thomas
433 56324ebe 2022-07-14 thomas if (qs->file != NULL && strlen(qs->file) > 0) {
434 56324ebe 2022-07-14 thomas error = got_commit_graph_open(&graph, file_path, 0);
435 56324ebe 2022-07-14 thomas if (error)
436 56324ebe 2022-07-14 thomas goto done;
437 56324ebe 2022-07-14 thomas } else {
438 56324ebe 2022-07-14 thomas error = got_commit_graph_open(&graph, in_repo_path, 0);
439 56324ebe 2022-07-14 thomas if (error)
440 56324ebe 2022-07-14 thomas goto done;
441 56324ebe 2022-07-14 thomas }
442 56324ebe 2022-07-14 thomas
443 56324ebe 2022-07-14 thomas error = got_commit_graph_iter_start(graph, id, repo, NULL, NULL);
444 56324ebe 2022-07-14 thomas if (error)
445 56324ebe 2022-07-14 thomas goto done;
446 56324ebe 2022-07-14 thomas
447 56324ebe 2022-07-14 thomas for (;;) {
448 56324ebe 2022-07-14 thomas if (limit_chk == ((limit * qs->page) - (limit - 1)) &&
449 56324ebe 2022-07-14 thomas commit_found == 0 && repo_commit->commit_id != NULL) {
450 56324ebe 2022-07-14 thomas t->prev_id = strdup(repo_commit->commit_id);
451 56324ebe 2022-07-14 thomas if (t->prev_id == NULL) {
452 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
453 56324ebe 2022-07-14 thomas goto done;
454 56324ebe 2022-07-14 thomas }
455 56324ebe 2022-07-14 thomas }
456 56324ebe 2022-07-14 thomas
457 56324ebe 2022-07-14 thomas error = got_commit_graph_iter_next(&id, graph, repo, NULL,
458 56324ebe 2022-07-14 thomas NULL);
459 56324ebe 2022-07-14 thomas if (error) {
460 56324ebe 2022-07-14 thomas if (error->code == GOT_ERR_ITER_COMPLETED)
461 56324ebe 2022-07-14 thomas error = NULL;
462 56324ebe 2022-07-14 thomas goto done;
463 56324ebe 2022-07-14 thomas }
464 56324ebe 2022-07-14 thomas if (id == NULL)
465 56324ebe 2022-07-14 thomas goto done;
466 56324ebe 2022-07-14 thomas
467 56324ebe 2022-07-14 thomas error = got_object_open_as_commit(&commit, repo, id);
468 56324ebe 2022-07-14 thomas if (error)
469 56324ebe 2022-07-14 thomas goto done;
470 56324ebe 2022-07-14 thomas
471 56324ebe 2022-07-14 thomas error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
472 56324ebe 2022-07-14 thomas NULL);
473 56324ebe 2022-07-14 thomas if (error)
474 56324ebe 2022-07-14 thomas goto done;
475 56324ebe 2022-07-14 thomas
476 56324ebe 2022-07-14 thomas error = got_get_repo_commit(c, repo_commit, commit,
477 56324ebe 2022-07-14 thomas &refs, id);
478 56324ebe 2022-07-14 thomas if (error)
479 56324ebe 2022-07-14 thomas goto done;
480 56324ebe 2022-07-14 thomas
481 56324ebe 2022-07-14 thomas if (qs->commit != NULL && commit_found == 0 && limit != 1) {
482 56324ebe 2022-07-14 thomas if (strcmp(qs->commit, repo_commit->commit_id) == 0)
483 56324ebe 2022-07-14 thomas commit_found = 1;
484 56324ebe 2022-07-14 thomas else if (qs->file != NULL && strlen(qs->file) > 0 &&
485 56324ebe 2022-07-14 thomas qs->page == 0)
486 56324ebe 2022-07-14 thomas commit_found = 1;
487 56324ebe 2022-07-14 thomas else {
488 56324ebe 2022-07-14 thomas limit_chk++;
489 56324ebe 2022-07-14 thomas free(id);
490 56324ebe 2022-07-14 thomas id = NULL;
491 56324ebe 2022-07-14 thomas continue;
492 56324ebe 2022-07-14 thomas }
493 56324ebe 2022-07-14 thomas }
494 56324ebe 2022-07-14 thomas
495 56324ebe 2022-07-14 thomas struct repo_commit *new_repo_commit = NULL;
496 56324ebe 2022-07-14 thomas error = got_init_repo_commit(&new_repo_commit);
497 56324ebe 2022-07-14 thomas if (error)
498 56324ebe 2022-07-14 thomas goto done;
499 56324ebe 2022-07-14 thomas
500 56324ebe 2022-07-14 thomas TAILQ_INSERT_TAIL(&t->repo_commits, new_repo_commit, entry);
501 56324ebe 2022-07-14 thomas
502 56324ebe 2022-07-14 thomas error = got_get_repo_commit(c, new_repo_commit, commit,
503 56324ebe 2022-07-14 thomas &refs, id);
504 56324ebe 2022-07-14 thomas if (error)
505 56324ebe 2022-07-14 thomas goto done;
506 56324ebe 2022-07-14 thomas
507 56324ebe 2022-07-14 thomas free(id);
508 56324ebe 2022-07-14 thomas id = NULL;
509 56324ebe 2022-07-14 thomas
510 56324ebe 2022-07-14 thomas if (limit == 1 && chk_multi == 0 &&
511 56324ebe 2022-07-14 thomas srv->max_commits_display != 1)
512 56324ebe 2022-07-14 thomas commit_found = 1;
513 56324ebe 2022-07-14 thomas else {
514 56324ebe 2022-07-14 thomas chk_multi = 1;
515 56324ebe 2022-07-14 thomas
516 56324ebe 2022-07-14 thomas /*
517 56324ebe 2022-07-14 thomas * check for one more commit before breaking,
518 56324ebe 2022-07-14 thomas * so we know whether to navigate through briefs
519 56324ebe 2022-07-14 thomas * commits and summary
520 56324ebe 2022-07-14 thomas */
521 56324ebe 2022-07-14 thomas if (chk_next && (qs->action == BRIEFS ||
522 56324ebe 2022-07-14 thomas qs->action == COMMITS || qs->action == SUMMARY)) {
523 56324ebe 2022-07-14 thomas t->next_id = strdup(new_repo_commit->commit_id);
524 56324ebe 2022-07-14 thomas if (t->next_id == NULL) {
525 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
526 56324ebe 2022-07-14 thomas goto done;
527 56324ebe 2022-07-14 thomas }
528 56324ebe 2022-07-14 thomas if (commit) {
529 56324ebe 2022-07-14 thomas got_object_commit_close(commit);
530 56324ebe 2022-07-14 thomas commit = NULL;
531 56324ebe 2022-07-14 thomas }
532 56324ebe 2022-07-14 thomas if (t->next_id == NULL) {
533 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
534 56324ebe 2022-07-14 thomas goto done;
535 56324ebe 2022-07-14 thomas }
536 56324ebe 2022-07-14 thomas TAILQ_REMOVE(&t->repo_commits, new_repo_commit,
537 56324ebe 2022-07-14 thomas entry);
538 56324ebe 2022-07-14 thomas gotweb_free_repo_commit(new_repo_commit);
539 56324ebe 2022-07-14 thomas goto done;
540 56324ebe 2022-07-14 thomas }
541 56324ebe 2022-07-14 thomas }
542 56324ebe 2022-07-14 thomas got_ref_list_free(&refs);
543 56324ebe 2022-07-14 thomas if (error || (limit && --limit == 0)) {
544 56324ebe 2022-07-14 thomas if (commit_found || (qs->file != NULL &&
545 56324ebe 2022-07-14 thomas strlen(qs->file) > 0))
546 56324ebe 2022-07-14 thomas if (chk_multi == 0)
547 56324ebe 2022-07-14 thomas break;
548 56324ebe 2022-07-14 thomas chk_next = 1;
549 56324ebe 2022-07-14 thomas }
550 56324ebe 2022-07-14 thomas if (commit) {
551 56324ebe 2022-07-14 thomas got_object_commit_close(commit);
552 56324ebe 2022-07-14 thomas commit = NULL;
553 56324ebe 2022-07-14 thomas }
554 56324ebe 2022-07-14 thomas }
555 56324ebe 2022-07-14 thomas done:
556 56324ebe 2022-07-14 thomas gotweb_free_repo_commit(repo_commit);
557 56324ebe 2022-07-14 thomas if (commit)
558 56324ebe 2022-07-14 thomas got_object_commit_close(commit);
559 56324ebe 2022-07-14 thomas if (graph)
560 56324ebe 2022-07-14 thomas got_commit_graph_close(graph);
561 56324ebe 2022-07-14 thomas got_ref_list_free(&refs);
562 56324ebe 2022-07-14 thomas free(file_path);
563 56324ebe 2022-07-14 thomas free(repo_path);
564 56324ebe 2022-07-14 thomas free(id);
565 56324ebe 2022-07-14 thomas return error;
566 56324ebe 2022-07-14 thomas }
567 56324ebe 2022-07-14 thomas
568 56324ebe 2022-07-14 thomas const struct got_error *
569 56324ebe 2022-07-14 thomas got_get_repo_tags(struct request *c, int limit)
570 56324ebe 2022-07-14 thomas {
571 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
572 56324ebe 2022-07-14 thomas struct got_object_id *id = NULL;
573 56324ebe 2022-07-14 thomas struct got_commit_object *commit = NULL;
574 56324ebe 2022-07-14 thomas struct got_reflist_head refs;
575 56324ebe 2022-07-14 thomas struct got_reference *ref;
576 56324ebe 2022-07-14 thomas struct got_reflist_entry *re;
577 56324ebe 2022-07-14 thomas struct server *srv = c->srv;
578 56324ebe 2022-07-14 thomas struct transport *t = c->t;
579 56324ebe 2022-07-14 thomas struct got_repository *repo = t->repo;
580 56324ebe 2022-07-14 thomas struct querystring *qs = t->qs;
581 56324ebe 2022-07-14 thomas struct repo_dir *repo_dir = t->repo_dir;
582 56324ebe 2022-07-14 thomas struct got_tag_object *tag = NULL;
583 56324ebe 2022-07-14 thomas struct repo_tag *rt = NULL, *trt = NULL;
584 56324ebe 2022-07-14 thomas char *in_repo_path = NULL, *repo_path = NULL, *id_str = NULL;
585 56324ebe 2022-07-14 thomas char *commit_msg = NULL, *commit_msg0 = NULL;
586 56324ebe 2022-07-14 thomas int chk_next = 0, chk_multi = 1, commit_found = 0, c_cnt = 0;
587 56324ebe 2022-07-14 thomas
588 56324ebe 2022-07-14 thomas TAILQ_INIT(&refs);
589 56324ebe 2022-07-14 thomas
590 56324ebe 2022-07-14 thomas if (asprintf(&repo_path, "%s/%s", srv->repos_path,
591 56324ebe 2022-07-14 thomas repo_dir->name) == -1)
592 56324ebe 2022-07-14 thomas return got_error_from_errno("asprintf");
593 56324ebe 2022-07-14 thomas
594 56324ebe 2022-07-14 thomas if (error)
595 56324ebe 2022-07-14 thomas return error;
596 56324ebe 2022-07-14 thomas
597 56324ebe 2022-07-14 thomas if (qs->commit == NULL && qs->action == TAGS) {
598 56324ebe 2022-07-14 thomas error = got_ref_open(&ref, repo, qs->headref, 0);
599 56324ebe 2022-07-14 thomas if (error)
600 56324ebe 2022-07-14 thomas goto err;
601 56324ebe 2022-07-14 thomas error = got_ref_resolve(&id, repo, ref);
602 56324ebe 2022-07-14 thomas got_ref_close(ref);
603 56324ebe 2022-07-14 thomas if (error)
604 56324ebe 2022-07-14 thomas goto err;
605 56324ebe 2022-07-14 thomas } else if (qs->commit == NULL && qs->action == TAG) {
606 56324ebe 2022-07-14 thomas error = got_error_msg(GOT_ERR_EOF, "commit id missing");
607 56324ebe 2022-07-14 thomas goto err;
608 56324ebe 2022-07-14 thomas } else {
609 56324ebe 2022-07-14 thomas error = got_repo_match_object_id_prefix(&id, qs->commit,
610 56324ebe 2022-07-14 thomas GOT_OBJ_TYPE_COMMIT, repo);
611 56324ebe 2022-07-14 thomas if (error)
612 56324ebe 2022-07-14 thomas goto err;
613 56324ebe 2022-07-14 thomas }
614 56324ebe 2022-07-14 thomas
615 56324ebe 2022-07-14 thomas if (qs->action != SUMMARY && qs->action != TAGS) {
616 56324ebe 2022-07-14 thomas error = got_object_open_as_commit(&commit, repo, id);
617 56324ebe 2022-07-14 thomas if (error)
618 56324ebe 2022-07-14 thomas goto err;
619 56324ebe 2022-07-14 thomas error = got_object_commit_get_logmsg(&commit_msg0, commit);
620 56324ebe 2022-07-14 thomas if (error)
621 56324ebe 2022-07-14 thomas goto err;
622 56324ebe 2022-07-14 thomas if (commit) {
623 56324ebe 2022-07-14 thomas got_object_commit_close(commit);
624 56324ebe 2022-07-14 thomas commit = NULL;
625 56324ebe 2022-07-14 thomas }
626 56324ebe 2022-07-14 thomas }
627 56324ebe 2022-07-14 thomas
628 56324ebe 2022-07-14 thomas error = got_repo_map_path(&in_repo_path, repo, repo_path);
629 56324ebe 2022-07-14 thomas if (error)
630 56324ebe 2022-07-14 thomas goto err;
631 56324ebe 2022-07-14 thomas
632 56324ebe 2022-07-14 thomas error = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags,
633 56324ebe 2022-07-14 thomas repo);
634 56324ebe 2022-07-14 thomas if (error)
635 56324ebe 2022-07-14 thomas goto err;
636 56324ebe 2022-07-14 thomas
637 56324ebe 2022-07-14 thomas if (limit == 1)
638 56324ebe 2022-07-14 thomas chk_multi = 0;
639 56324ebe 2022-07-14 thomas
640 56324ebe 2022-07-14 thomas /*
641 56324ebe 2022-07-14 thomas * XXX: again, see previous message about caching
642 56324ebe 2022-07-14 thomas */
643 56324ebe 2022-07-14 thomas
644 56324ebe 2022-07-14 thomas TAILQ_FOREACH(re, &refs, entry) {
645 56324ebe 2022-07-14 thomas struct repo_tag *new_repo_tag = NULL;
646 56324ebe 2022-07-14 thomas error = got_init_repo_tag(&new_repo_tag);
647 56324ebe 2022-07-14 thomas if (error)
648 56324ebe 2022-07-14 thomas goto err;
649 56324ebe 2022-07-14 thomas
650 56324ebe 2022-07-14 thomas TAILQ_INSERT_TAIL(&t->repo_tags, new_repo_tag, entry);
651 56324ebe 2022-07-14 thomas
652 56324ebe 2022-07-14 thomas new_repo_tag->tag_name = strdup(got_ref_get_name(re->ref));
653 56324ebe 2022-07-14 thomas if (new_repo_tag->tag_name == NULL) {
654 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
655 56324ebe 2022-07-14 thomas goto err;
656 56324ebe 2022-07-14 thomas }
657 56324ebe 2022-07-14 thomas
658 56324ebe 2022-07-14 thomas error = got_ref_resolve(&id, repo, re->ref);
659 56324ebe 2022-07-14 thomas if (error)
660 56324ebe 2022-07-14 thomas goto done;
661 56324ebe 2022-07-14 thomas
662 56324ebe 2022-07-14 thomas error = got_object_open_as_tag(&tag, repo, id);
663 56324ebe 2022-07-14 thomas if (error) {
664 56324ebe 2022-07-14 thomas if (error->code != GOT_ERR_OBJ_TYPE) {
665 56324ebe 2022-07-14 thomas free(id);
666 56324ebe 2022-07-14 thomas id = NULL;
667 56324ebe 2022-07-14 thomas goto done;
668 56324ebe 2022-07-14 thomas }
669 56324ebe 2022-07-14 thomas /* "lightweight" tag */
670 56324ebe 2022-07-14 thomas error = got_object_open_as_commit(&commit, repo, id);
671 56324ebe 2022-07-14 thomas if (error) {
672 56324ebe 2022-07-14 thomas free(id);
673 56324ebe 2022-07-14 thomas id = NULL;
674 56324ebe 2022-07-14 thomas goto done;
675 56324ebe 2022-07-14 thomas }
676 56324ebe 2022-07-14 thomas new_repo_tag->tagger =
677 56324ebe 2022-07-14 thomas strdup(got_object_commit_get_committer(commit));
678 56324ebe 2022-07-14 thomas if (new_repo_tag->tagger == NULL) {
679 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
680 56324ebe 2022-07-14 thomas goto err;
681 56324ebe 2022-07-14 thomas }
682 56324ebe 2022-07-14 thomas new_repo_tag->tagger_time =
683 56324ebe 2022-07-14 thomas got_object_commit_get_committer_time(commit);
684 56324ebe 2022-07-14 thomas error = got_object_id_str(&id_str, id);
685 56324ebe 2022-07-14 thomas if (error)
686 56324ebe 2022-07-14 thomas goto err;
687 56324ebe 2022-07-14 thomas free(id);
688 56324ebe 2022-07-14 thomas id = NULL;
689 56324ebe 2022-07-14 thomas } else {
690 56324ebe 2022-07-14 thomas free(id);
691 56324ebe 2022-07-14 thomas id = NULL;
692 56324ebe 2022-07-14 thomas new_repo_tag->tagger =
693 56324ebe 2022-07-14 thomas strdup(got_object_tag_get_tagger(tag));
694 56324ebe 2022-07-14 thomas if (new_repo_tag->tagger == NULL) {
695 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
696 56324ebe 2022-07-14 thomas goto err;
697 56324ebe 2022-07-14 thomas }
698 56324ebe 2022-07-14 thomas new_repo_tag->tagger_time =
699 56324ebe 2022-07-14 thomas got_object_tag_get_tagger_time(tag);
700 56324ebe 2022-07-14 thomas error = got_object_id_str(&id_str,
701 56324ebe 2022-07-14 thomas got_object_tag_get_object_id(tag));
702 56324ebe 2022-07-14 thomas if (error)
703 56324ebe 2022-07-14 thomas goto err;
704 56324ebe 2022-07-14 thomas }
705 56324ebe 2022-07-14 thomas
706 56324ebe 2022-07-14 thomas new_repo_tag->commit_id = strdup(id_str);
707 56324ebe 2022-07-14 thomas if (new_repo_tag->commit_id == NULL)
708 56324ebe 2022-07-14 thomas goto err;
709 56324ebe 2022-07-14 thomas
710 56324ebe 2022-07-14 thomas if (commit_found == 0 && qs->commit != NULL &&
711 56324ebe 2022-07-14 thomas strncmp(id_str, qs->commit, strlen(id_str)) != 0)
712 56324ebe 2022-07-14 thomas continue;
713 56324ebe 2022-07-14 thomas else
714 56324ebe 2022-07-14 thomas commit_found = 1;
715 56324ebe 2022-07-14 thomas
716 56324ebe 2022-07-14 thomas t->tag_count++;
717 56324ebe 2022-07-14 thomas
718 56324ebe 2022-07-14 thomas /*
719 56324ebe 2022-07-14 thomas * check for one more commit before breaking,
720 56324ebe 2022-07-14 thomas * so we know whether to navigate through briefs
721 56324ebe 2022-07-14 thomas * commits and summary
722 56324ebe 2022-07-14 thomas */
723 56324ebe 2022-07-14 thomas if (chk_next) {
724 56324ebe 2022-07-14 thomas t->next_id = strdup(new_repo_tag->commit_id);
725 56324ebe 2022-07-14 thomas if (t->next_id == NULL) {
726 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
727 56324ebe 2022-07-14 thomas goto err;
728 56324ebe 2022-07-14 thomas }
729 56324ebe 2022-07-14 thomas if (commit) {
730 56324ebe 2022-07-14 thomas got_object_commit_close(commit);
731 56324ebe 2022-07-14 thomas commit = NULL;
732 56324ebe 2022-07-14 thomas }
733 56324ebe 2022-07-14 thomas if (t->next_id == NULL) {
734 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
735 56324ebe 2022-07-14 thomas goto err;
736 56324ebe 2022-07-14 thomas }
737 56324ebe 2022-07-14 thomas TAILQ_REMOVE(&t->repo_tags, new_repo_tag, entry);
738 56324ebe 2022-07-14 thomas gotweb_free_repo_tag(new_repo_tag);
739 56324ebe 2022-07-14 thomas goto done;
740 56324ebe 2022-07-14 thomas }
741 56324ebe 2022-07-14 thomas
742 56324ebe 2022-07-14 thomas if (commit) {
743 56324ebe 2022-07-14 thomas error = got_object_commit_get_logmsg(&new_repo_tag->
744 56324ebe 2022-07-14 thomas tag_commit, commit);
745 56324ebe 2022-07-14 thomas if (error)
746 56324ebe 2022-07-14 thomas goto done;
747 56324ebe 2022-07-14 thomas got_object_commit_close(commit);
748 56324ebe 2022-07-14 thomas commit = NULL;
749 56324ebe 2022-07-14 thomas } else {
750 56324ebe 2022-07-14 thomas new_repo_tag->tag_commit =
751 56324ebe 2022-07-14 thomas strdup(got_object_tag_get_message(tag));
752 56324ebe 2022-07-14 thomas if (new_repo_tag->tag_commit == NULL) {
753 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
754 56324ebe 2022-07-14 thomas goto done;
755 56324ebe 2022-07-14 thomas }
756 56324ebe 2022-07-14 thomas }
757 56324ebe 2022-07-14 thomas
758 56324ebe 2022-07-14 thomas while (*new_repo_tag->tag_commit == '\n')
759 56324ebe 2022-07-14 thomas new_repo_tag->tag_commit++;
760 56324ebe 2022-07-14 thomas
761 56324ebe 2022-07-14 thomas if (qs->action != SUMMARY && qs->action != TAGS) {
762 56324ebe 2022-07-14 thomas commit_msg = commit_msg0;
763 56324ebe 2022-07-14 thomas while (*commit_msg == '\n')
764 56324ebe 2022-07-14 thomas commit_msg++;
765 56324ebe 2022-07-14 thomas
766 56324ebe 2022-07-14 thomas new_repo_tag->commit_msg = strdup(commit_msg);
767 56324ebe 2022-07-14 thomas if (new_repo_tag->commit_msg == NULL) {
768 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
769 56324ebe 2022-07-14 thomas free(commit_msg0);
770 56324ebe 2022-07-14 thomas goto err;
771 56324ebe 2022-07-14 thomas }
772 56324ebe 2022-07-14 thomas free(commit_msg0);
773 56324ebe 2022-07-14 thomas }
774 56324ebe 2022-07-14 thomas
775 56324ebe 2022-07-14 thomas if (limit && --limit == 0) {
776 56324ebe 2022-07-14 thomas if (chk_multi == 0)
777 56324ebe 2022-07-14 thomas break;
778 56324ebe 2022-07-14 thomas chk_next = 1;
779 56324ebe 2022-07-14 thomas }
780 56324ebe 2022-07-14 thomas free(id);
781 56324ebe 2022-07-14 thomas id = NULL;
782 56324ebe 2022-07-14 thomas }
783 56324ebe 2022-07-14 thomas
784 56324ebe 2022-07-14 thomas done:
785 56324ebe 2022-07-14 thomas /*
786 56324ebe 2022-07-14 thomas * we have tailq populated, so find previous commit id
787 56324ebe 2022-07-14 thomas * for navigation through briefs and commits
788 56324ebe 2022-07-14 thomas */
789 56324ebe 2022-07-14 thomas if (t->tag_count == 0) {
790 56324ebe 2022-07-14 thomas TAILQ_FOREACH_SAFE(rt, &t->repo_tags, entry, trt) {
791 56324ebe 2022-07-14 thomas TAILQ_REMOVE(&t->repo_tags, rt, entry);
792 56324ebe 2022-07-14 thomas gotweb_free_repo_tag(rt);
793 56324ebe 2022-07-14 thomas }
794 56324ebe 2022-07-14 thomas }
795 56324ebe 2022-07-14 thomas if (t->tag_count > 0 && t->prev_id == NULL && qs->commit != NULL) {
796 56324ebe 2022-07-14 thomas commit_found = 0;
797 56324ebe 2022-07-14 thomas TAILQ_FOREACH_REVERSE(rt, &t->repo_tags, repo_tags_head,
798 56324ebe 2022-07-14 thomas entry) {
799 56324ebe 2022-07-14 thomas if (commit_found == 0 && rt->commit_id != NULL &&
800 56324ebe 2022-07-14 thomas strcmp(qs->commit, rt->commit_id) != 0) {
801 56324ebe 2022-07-14 thomas continue;
802 56324ebe 2022-07-14 thomas } else
803 56324ebe 2022-07-14 thomas commit_found = 1;
804 56324ebe 2022-07-14 thomas if (c_cnt == srv->max_commits_display ||
805 56324ebe 2022-07-14 thomas rt == TAILQ_FIRST(&t->repo_tags)) {
806 56324ebe 2022-07-14 thomas t->prev_id = strdup(rt->commit_id);
807 56324ebe 2022-07-14 thomas if (t->prev_id == NULL)
808 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
809 56324ebe 2022-07-14 thomas break;
810 56324ebe 2022-07-14 thomas }
811 56324ebe 2022-07-14 thomas c_cnt++;
812 56324ebe 2022-07-14 thomas }
813 56324ebe 2022-07-14 thomas }
814 56324ebe 2022-07-14 thomas err:
815 56324ebe 2022-07-14 thomas if (commit)
816 56324ebe 2022-07-14 thomas got_object_commit_close(commit);
817 56324ebe 2022-07-14 thomas got_ref_list_free(&refs);
818 56324ebe 2022-07-14 thomas free(repo_path);
819 56324ebe 2022-07-14 thomas free(id);
820 56324ebe 2022-07-14 thomas return error;
821 56324ebe 2022-07-14 thomas }
822 56324ebe 2022-07-14 thomas
823 56324ebe 2022-07-14 thomas const struct got_error *
824 56324ebe 2022-07-14 thomas got_output_repo_tree(struct request *c)
825 56324ebe 2022-07-14 thomas {
826 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
827 56324ebe 2022-07-14 thomas struct transport *t = c->t;
828 56324ebe 2022-07-14 thomas struct got_commit_object *commit = NULL;
829 56324ebe 2022-07-14 thomas struct got_repository *repo = t->repo;
830 56324ebe 2022-07-14 thomas struct querystring *qs = t->qs;
831 56324ebe 2022-07-14 thomas struct repo_commit *rc = NULL;
832 56324ebe 2022-07-14 thomas struct got_object_id *tree_id = NULL, *commit_id = NULL;
833 56324ebe 2022-07-14 thomas struct got_reflist_head refs;
834 56324ebe 2022-07-14 thomas struct got_tree_object *tree = NULL;
835 56324ebe 2022-07-14 thomas struct repo_dir *repo_dir = t->repo_dir;
836 56324ebe 2022-07-14 thomas char *id_str = NULL;
837 56324ebe 2022-07-14 thomas char *path = NULL, *in_repo_path = NULL, *build_folder = NULL;
838 56324ebe 2022-07-14 thomas char *modestr = NULL, *name = NULL, *class = NULL;
839 56324ebe 2022-07-14 thomas int nentries, i, class_flip = 0;
840 56324ebe 2022-07-14 thomas
841 56324ebe 2022-07-14 thomas TAILQ_INIT(&refs);
842 56324ebe 2022-07-14 thomas
843 56324ebe 2022-07-14 thomas rc = TAILQ_FIRST(&t->repo_commits);
844 56324ebe 2022-07-14 thomas
845 56324ebe 2022-07-14 thomas if (qs->folder != NULL) {
846 56324ebe 2022-07-14 thomas path = strdup(qs->folder);
847 56324ebe 2022-07-14 thomas if (path == NULL) {
848 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
849 56324ebe 2022-07-14 thomas goto done;
850 56324ebe 2022-07-14 thomas }
851 56324ebe 2022-07-14 thomas } else {
852 56324ebe 2022-07-14 thomas error = got_repo_map_path(&in_repo_path, repo, repo_dir->path);
853 56324ebe 2022-07-14 thomas if (error)
854 56324ebe 2022-07-14 thomas goto done;
855 56324ebe 2022-07-14 thomas free(path);
856 56324ebe 2022-07-14 thomas path = in_repo_path;
857 56324ebe 2022-07-14 thomas }
858 56324ebe 2022-07-14 thomas
859 56324ebe 2022-07-14 thomas error = got_repo_match_object_id(&commit_id, NULL, rc->commit_id,
860 56324ebe 2022-07-14 thomas GOT_OBJ_TYPE_COMMIT, &refs, repo);
861 56324ebe 2022-07-14 thomas if (error)
862 56324ebe 2022-07-14 thomas goto done;
863 56324ebe 2022-07-14 thomas
864 56324ebe 2022-07-14 thomas error = got_object_open_as_commit(&commit, repo, commit_id);
865 56324ebe 2022-07-14 thomas if (error)
866 56324ebe 2022-07-14 thomas goto done;
867 56324ebe 2022-07-14 thomas
868 56324ebe 2022-07-14 thomas error = got_object_id_by_path(&tree_id, repo, commit, path);
869 56324ebe 2022-07-14 thomas if (error)
870 56324ebe 2022-07-14 thomas goto done;
871 56324ebe 2022-07-14 thomas
872 56324ebe 2022-07-14 thomas error = got_object_open_as_tree(&tree, repo, tree_id);
873 56324ebe 2022-07-14 thomas if (error)
874 56324ebe 2022-07-14 thomas goto done;
875 56324ebe 2022-07-14 thomas
876 56324ebe 2022-07-14 thomas nentries = got_object_tree_get_nentries(tree);
877 56324ebe 2022-07-14 thomas
878 56324ebe 2022-07-14 thomas for (i = 0; i < nentries; i++) {
879 56324ebe 2022-07-14 thomas struct got_tree_entry *te;
880 56324ebe 2022-07-14 thomas mode_t mode;
881 56324ebe 2022-07-14 thomas
882 56324ebe 2022-07-14 thomas te = got_object_tree_get_entry(tree, i);
883 56324ebe 2022-07-14 thomas
884 56324ebe 2022-07-14 thomas error = got_object_id_str(&id_str, got_tree_entry_get_id(te));
885 56324ebe 2022-07-14 thomas if (error)
886 56324ebe 2022-07-14 thomas goto done;
887 56324ebe 2022-07-14 thomas
888 56324ebe 2022-07-14 thomas modestr = strdup("");
889 56324ebe 2022-07-14 thomas if (modestr == NULL) {
890 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
891 56324ebe 2022-07-14 thomas goto done;
892 56324ebe 2022-07-14 thomas }
893 56324ebe 2022-07-14 thomas mode = got_tree_entry_get_mode(te);
894 56324ebe 2022-07-14 thomas if (got_object_tree_entry_is_submodule(te)) {
895 56324ebe 2022-07-14 thomas free(modestr);
896 56324ebe 2022-07-14 thomas modestr = strdup("$");
897 56324ebe 2022-07-14 thomas if (modestr == NULL) {
898 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
899 56324ebe 2022-07-14 thomas goto done;
900 56324ebe 2022-07-14 thomas }
901 56324ebe 2022-07-14 thomas } else if (S_ISLNK(mode)) {
902 56324ebe 2022-07-14 thomas free(modestr);
903 56324ebe 2022-07-14 thomas modestr = strdup("@");
904 56324ebe 2022-07-14 thomas if (modestr == NULL) {
905 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
906 56324ebe 2022-07-14 thomas goto done;
907 56324ebe 2022-07-14 thomas }
908 56324ebe 2022-07-14 thomas } else if (S_ISDIR(mode)) {
909 56324ebe 2022-07-14 thomas free(modestr);
910 56324ebe 2022-07-14 thomas modestr = strdup("/");
911 56324ebe 2022-07-14 thomas if (modestr == NULL) {
912 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
913 56324ebe 2022-07-14 thomas goto done;
914 56324ebe 2022-07-14 thomas }
915 56324ebe 2022-07-14 thomas } else if (mode & S_IXUSR) {
916 56324ebe 2022-07-14 thomas free(modestr);
917 56324ebe 2022-07-14 thomas modestr = strdup("*");
918 56324ebe 2022-07-14 thomas if (modestr == NULL) {
919 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
920 56324ebe 2022-07-14 thomas goto done;
921 56324ebe 2022-07-14 thomas }
922 56324ebe 2022-07-14 thomas }
923 56324ebe 2022-07-14 thomas
924 56324ebe 2022-07-14 thomas if (class_flip == 0) {
925 56324ebe 2022-07-14 thomas class = strdup("back_lightgray");
926 56324ebe 2022-07-14 thomas if (class == NULL) {
927 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
928 56324ebe 2022-07-14 thomas goto done;
929 56324ebe 2022-07-14 thomas }
930 56324ebe 2022-07-14 thomas class_flip = 1;
931 56324ebe 2022-07-14 thomas } else {
932 56324ebe 2022-07-14 thomas class = strdup("back_white");
933 56324ebe 2022-07-14 thomas if (class == NULL) {
934 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
935 56324ebe 2022-07-14 thomas goto done;
936 56324ebe 2022-07-14 thomas }
937 56324ebe 2022-07-14 thomas class_flip = 0;
938 56324ebe 2022-07-14 thomas }
939 56324ebe 2022-07-14 thomas
940 56324ebe 2022-07-14 thomas name = strdup(got_tree_entry_get_name(te));
941 56324ebe 2022-07-14 thomas if (name == NULL) {
942 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
943 56324ebe 2022-07-14 thomas goto done;
944 56324ebe 2022-07-14 thomas }
945 56324ebe 2022-07-14 thomas if (S_ISDIR(mode)) {
946 56324ebe 2022-07-14 thomas if (asprintf(&build_folder, "%s/%s",
947 56324ebe 2022-07-14 thomas qs->folder ? qs->folder : "",
948 56324ebe 2022-07-14 thomas got_tree_entry_get_name(te)) == -1) {
949 56324ebe 2022-07-14 thomas error = got_error_from_errno("asprintf");
950 56324ebe 2022-07-14 thomas goto done;
951 56324ebe 2022-07-14 thomas }
952 56324ebe 2022-07-14 thomas
953 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c,
954 56324ebe 2022-07-14 thomas "<div id='tree_wrapper'>\n") == -1)
955 56324ebe 2022-07-14 thomas goto done;
956 56324ebe 2022-07-14 thomas
957 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<div id='tree_line' "
958 56324ebe 2022-07-14 thomas "class='") == -1)
959 56324ebe 2022-07-14 thomas goto done;
960 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, class) == -1)
961 56324ebe 2022-07-14 thomas goto done;
962 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "'>") == -1)
963 56324ebe 2022-07-14 thomas goto done;
964 56324ebe 2022-07-14 thomas
965 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<a class='diff_directory' "
966 56324ebe 2022-07-14 thomas "href='?index_page=") == -1)
967 56324ebe 2022-07-14 thomas goto done;
968 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->index_page_str) == -1)
969 56324ebe 2022-07-14 thomas goto done;
970 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&path=") == -1)
971 56324ebe 2022-07-14 thomas goto done;
972 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->path) == -1)
973 56324ebe 2022-07-14 thomas goto done;
974 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&action=tree") == -1)
975 56324ebe 2022-07-14 thomas goto done;
976 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&commit=") == -1)
977 56324ebe 2022-07-14 thomas goto done;
978 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, rc->commit_id) == -1)
979 56324ebe 2022-07-14 thomas goto done;
980 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&folder=") == -1)
981 56324ebe 2022-07-14 thomas goto done;
982 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, build_folder) == -1)
983 56324ebe 2022-07-14 thomas goto done;
984 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "'>") == -1)
985 56324ebe 2022-07-14 thomas goto done;
986 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, name) == -1)
987 56324ebe 2022-07-14 thomas goto done;
988 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, modestr) == -1)
989 56324ebe 2022-07-14 thomas goto done;
990 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</a>") == -1)
991 56324ebe 2022-07-14 thomas goto done;
992 56324ebe 2022-07-14 thomas
993 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>\n") == -1)
994 56324ebe 2022-07-14 thomas goto done;
995 56324ebe 2022-07-14 thomas
996 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<div id='tree_line_blank' "
997 56324ebe 2022-07-14 thomas "class='") == -1)
998 56324ebe 2022-07-14 thomas goto done;
999 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, class) == -1)
1000 56324ebe 2022-07-14 thomas goto done;
1001 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "'>") == -1)
1002 56324ebe 2022-07-14 thomas goto done;
1003 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&nbsp;") == -1)
1004 56324ebe 2022-07-14 thomas goto done;
1005 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>\n") == -1)
1006 56324ebe 2022-07-14 thomas goto done;
1007 56324ebe 2022-07-14 thomas
1008 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>\n") == -1)
1009 56324ebe 2022-07-14 thomas goto done;
1010 56324ebe 2022-07-14 thomas
1011 56324ebe 2022-07-14 thomas } else {
1012 56324ebe 2022-07-14 thomas free(name);
1013 56324ebe 2022-07-14 thomas name = strdup(got_tree_entry_get_name(te));
1014 56324ebe 2022-07-14 thomas if (name == NULL) {
1015 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1016 56324ebe 2022-07-14 thomas goto done;
1017 56324ebe 2022-07-14 thomas }
1018 56324ebe 2022-07-14 thomas
1019 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c,
1020 56324ebe 2022-07-14 thomas "<div id='tree_wrapper'>\n") == -1)
1021 56324ebe 2022-07-14 thomas goto done;
1022 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<div id='tree_line' "
1023 56324ebe 2022-07-14 thomas "class='") == -1)
1024 56324ebe 2022-07-14 thomas goto done;
1025 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, class) == -1)
1026 56324ebe 2022-07-14 thomas goto done;
1027 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "'>") == -1)
1028 56324ebe 2022-07-14 thomas goto done;
1029 56324ebe 2022-07-14 thomas
1030 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c,
1031 56324ebe 2022-07-14 thomas "<a href='?index_page=") == -1)
1032 56324ebe 2022-07-14 thomas goto done;
1033 56324ebe 2022-07-14 thomas
1034 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->index_page_str) == -1)
1035 56324ebe 2022-07-14 thomas goto done;
1036 56324ebe 2022-07-14 thomas
1037 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&path=") == -1)
1038 56324ebe 2022-07-14 thomas goto done;
1039 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->path) == -1)
1040 56324ebe 2022-07-14 thomas goto done;
1041 56324ebe 2022-07-14 thomas
1042 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&action=blob") == -1)
1043 56324ebe 2022-07-14 thomas goto done;
1044 56324ebe 2022-07-14 thomas
1045 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&commit=") == -1)
1046 56324ebe 2022-07-14 thomas goto done;
1047 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, rc->commit_id) == -1)
1048 56324ebe 2022-07-14 thomas goto done;
1049 56324ebe 2022-07-14 thomas
1050 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&folder=") == -1)
1051 56324ebe 2022-07-14 thomas goto done;
1052 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->folder) == -1)
1053 56324ebe 2022-07-14 thomas goto done;
1054 56324ebe 2022-07-14 thomas
1055 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&file=") == -1)
1056 56324ebe 2022-07-14 thomas goto done;
1057 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, name) == -1)
1058 56324ebe 2022-07-14 thomas goto done;
1059 56324ebe 2022-07-14 thomas
1060 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "'>") == -1)
1061 56324ebe 2022-07-14 thomas goto done;
1062 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, name) == -1)
1063 56324ebe 2022-07-14 thomas goto done;
1064 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, modestr) == -1)
1065 56324ebe 2022-07-14 thomas goto done;
1066 56324ebe 2022-07-14 thomas
1067 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</a>") == -1)
1068 56324ebe 2022-07-14 thomas goto done;
1069 56324ebe 2022-07-14 thomas
1070 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>\n") == -1)
1071 56324ebe 2022-07-14 thomas goto done;
1072 56324ebe 2022-07-14 thomas
1073 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<div id='tree_line_blank' "
1074 56324ebe 2022-07-14 thomas "class='") == -1)
1075 56324ebe 2022-07-14 thomas goto done;
1076 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, class) == -1)
1077 56324ebe 2022-07-14 thomas goto done;
1078 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "'>") == -1)
1079 56324ebe 2022-07-14 thomas goto done;
1080 56324ebe 2022-07-14 thomas
1081 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c,
1082 56324ebe 2022-07-14 thomas "<a href='?index_page=") == -1)
1083 56324ebe 2022-07-14 thomas goto done;
1084 56324ebe 2022-07-14 thomas
1085 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->index_page_str) == -1)
1086 56324ebe 2022-07-14 thomas goto done;
1087 56324ebe 2022-07-14 thomas
1088 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&path=") == -1)
1089 56324ebe 2022-07-14 thomas goto done;
1090 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->path) == -1)
1091 56324ebe 2022-07-14 thomas goto done;
1092 56324ebe 2022-07-14 thomas
1093 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&action=commits") == -1)
1094 56324ebe 2022-07-14 thomas goto done;
1095 56324ebe 2022-07-14 thomas
1096 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&commit=") == -1)
1097 56324ebe 2022-07-14 thomas goto done;
1098 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, rc->commit_id) == -1)
1099 56324ebe 2022-07-14 thomas goto done;
1100 56324ebe 2022-07-14 thomas
1101 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&folder=") == -1)
1102 56324ebe 2022-07-14 thomas goto done;
1103 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->folder) == -1)
1104 56324ebe 2022-07-14 thomas goto done;
1105 56324ebe 2022-07-14 thomas
1106 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&file=") == -1)
1107 56324ebe 2022-07-14 thomas goto done;
1108 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, name) == -1)
1109 56324ebe 2022-07-14 thomas goto done;
1110 56324ebe 2022-07-14 thomas
1111 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "'>") == -1)
1112 56324ebe 2022-07-14 thomas goto done;
1113 56324ebe 2022-07-14 thomas
1114 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "commits") == -1)
1115 56324ebe 2022-07-14 thomas goto done;
1116 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</a>\n") == -1)
1117 56324ebe 2022-07-14 thomas goto done;
1118 56324ebe 2022-07-14 thomas
1119 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, " | \n") == -1)
1120 56324ebe 2022-07-14 thomas goto done;
1121 56324ebe 2022-07-14 thomas
1122 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c,
1123 56324ebe 2022-07-14 thomas "<a href='?index_page=") == -1)
1124 56324ebe 2022-07-14 thomas goto done;
1125 56324ebe 2022-07-14 thomas
1126 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->index_page_str) == -1)
1127 56324ebe 2022-07-14 thomas goto done;
1128 56324ebe 2022-07-14 thomas
1129 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&path=") == -1)
1130 56324ebe 2022-07-14 thomas goto done;
1131 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->path) == -1)
1132 56324ebe 2022-07-14 thomas goto done;
1133 56324ebe 2022-07-14 thomas
1134 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&action=blame") == -1)
1135 56324ebe 2022-07-14 thomas goto done;
1136 56324ebe 2022-07-14 thomas
1137 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&commit=") == -1)
1138 56324ebe 2022-07-14 thomas goto done;
1139 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, rc->commit_id) == -1)
1140 56324ebe 2022-07-14 thomas goto done;
1141 56324ebe 2022-07-14 thomas
1142 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&folder=") == -1)
1143 56324ebe 2022-07-14 thomas goto done;
1144 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->folder) == -1)
1145 56324ebe 2022-07-14 thomas goto done;
1146 56324ebe 2022-07-14 thomas
1147 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&file=") == -1)
1148 56324ebe 2022-07-14 thomas goto done;
1149 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, name) == -1)
1150 56324ebe 2022-07-14 thomas goto done;
1151 56324ebe 2022-07-14 thomas
1152 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "'>") == -1)
1153 56324ebe 2022-07-14 thomas goto done;
1154 56324ebe 2022-07-14 thomas
1155 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "blame") == -1)
1156 56324ebe 2022-07-14 thomas goto done;
1157 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</a>\n") == -1)
1158 56324ebe 2022-07-14 thomas goto done;
1159 56324ebe 2022-07-14 thomas
1160 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>\n") == -1)
1161 56324ebe 2022-07-14 thomas goto done;
1162 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>\n") == -1)
1163 56324ebe 2022-07-14 thomas goto done;
1164 56324ebe 2022-07-14 thomas }
1165 56324ebe 2022-07-14 thomas free(id_str);
1166 56324ebe 2022-07-14 thomas id_str = NULL;
1167 56324ebe 2022-07-14 thomas free(build_folder);
1168 56324ebe 2022-07-14 thomas build_folder = NULL;
1169 56324ebe 2022-07-14 thomas free(name);
1170 56324ebe 2022-07-14 thomas name = NULL;
1171 56324ebe 2022-07-14 thomas free(modestr);
1172 56324ebe 2022-07-14 thomas modestr = NULL;
1173 56324ebe 2022-07-14 thomas free(class);
1174 56324ebe 2022-07-14 thomas class = NULL;
1175 56324ebe 2022-07-14 thomas }
1176 56324ebe 2022-07-14 thomas done:
1177 56324ebe 2022-07-14 thomas free(id_str);
1178 56324ebe 2022-07-14 thomas free(build_folder);
1179 56324ebe 2022-07-14 thomas free(modestr);
1180 56324ebe 2022-07-14 thomas free(path);
1181 56324ebe 2022-07-14 thomas free(name);
1182 56324ebe 2022-07-14 thomas free(class);
1183 56324ebe 2022-07-14 thomas got_ref_list_free(&refs);
1184 56324ebe 2022-07-14 thomas if (commit)
1185 56324ebe 2022-07-14 thomas got_object_commit_close(commit);
1186 56324ebe 2022-07-14 thomas free(commit_id);
1187 56324ebe 2022-07-14 thomas free(tree_id);
1188 56324ebe 2022-07-14 thomas return error;
1189 56324ebe 2022-07-14 thomas }
1190 56324ebe 2022-07-14 thomas
1191 56324ebe 2022-07-14 thomas const struct got_error *
1192 56324ebe 2022-07-14 thomas got_output_file_blob(struct request *c)
1193 56324ebe 2022-07-14 thomas {
1194 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
1195 56324ebe 2022-07-14 thomas struct transport *t = c->t;
1196 56324ebe 2022-07-14 thomas struct got_repository *repo = t->repo;
1197 56324ebe 2022-07-14 thomas struct querystring *qs = c->t->qs;
1198 56324ebe 2022-07-14 thomas struct got_commit_object *commit = NULL;
1199 56324ebe 2022-07-14 thomas struct got_object_id *commit_id = NULL;
1200 56324ebe 2022-07-14 thomas struct got_reflist_head refs;
1201 56324ebe 2022-07-14 thomas struct got_blob_object *blob = NULL;
1202 56324ebe 2022-07-14 thomas char *path = NULL, *in_repo_path = NULL;
1203 56324ebe 2022-07-14 thomas int obj_type, set_mime = 0, type = 0, fd = -1;
1204 56324ebe 2022-07-14 thomas char *buf_output = NULL;
1205 56324ebe 2022-07-14 thomas size_t len, hdrlen;
1206 56324ebe 2022-07-14 thomas const uint8_t *buf;
1207 56324ebe 2022-07-14 thomas
1208 56324ebe 2022-07-14 thomas TAILQ_INIT(&refs);
1209 56324ebe 2022-07-14 thomas
1210 56324ebe 2022-07-14 thomas if (asprintf(&path, "%s%s%s", qs->folder ? qs->folder : "",
1211 56324ebe 2022-07-14 thomas qs->folder ? "/" : "", qs->file) == -1) {
1212 56324ebe 2022-07-14 thomas error = got_error_from_errno("asprintf");
1213 56324ebe 2022-07-14 thomas goto done;
1214 56324ebe 2022-07-14 thomas }
1215 56324ebe 2022-07-14 thomas
1216 56324ebe 2022-07-14 thomas error = got_repo_map_path(&in_repo_path, repo, path);
1217 56324ebe 2022-07-14 thomas if (error)
1218 56324ebe 2022-07-14 thomas goto done;
1219 56324ebe 2022-07-14 thomas
1220 56324ebe 2022-07-14 thomas error = got_repo_match_object_id(&commit_id, NULL, qs->commit,
1221 56324ebe 2022-07-14 thomas GOT_OBJ_TYPE_COMMIT, &refs, repo);
1222 56324ebe 2022-07-14 thomas if (error)
1223 56324ebe 2022-07-14 thomas goto done;
1224 56324ebe 2022-07-14 thomas
1225 56324ebe 2022-07-14 thomas error = got_object_open_as_commit(&commit, repo, commit_id);
1226 56324ebe 2022-07-14 thomas if (error)
1227 56324ebe 2022-07-14 thomas goto done;
1228 56324ebe 2022-07-14 thomas
1229 56324ebe 2022-07-14 thomas error = got_object_id_by_path(&commit_id, repo, commit, in_repo_path);
1230 56324ebe 2022-07-14 thomas if (error)
1231 56324ebe 2022-07-14 thomas goto done;
1232 56324ebe 2022-07-14 thomas
1233 56324ebe 2022-07-14 thomas if (commit_id == NULL) {
1234 56324ebe 2022-07-14 thomas error = got_error(GOT_ERR_NO_OBJ);
1235 56324ebe 2022-07-14 thomas goto done;
1236 56324ebe 2022-07-14 thomas }
1237 56324ebe 2022-07-14 thomas
1238 56324ebe 2022-07-14 thomas error = got_object_get_type(&obj_type, repo, commit_id);
1239 56324ebe 2022-07-14 thomas if (error)
1240 56324ebe 2022-07-14 thomas goto done;
1241 56324ebe 2022-07-14 thomas
1242 56324ebe 2022-07-14 thomas if (obj_type != GOT_OBJ_TYPE_BLOB) {
1243 56324ebe 2022-07-14 thomas error = got_error(GOT_ERR_OBJ_TYPE);
1244 56324ebe 2022-07-14 thomas goto done;
1245 56324ebe 2022-07-14 thomas }
1246 56324ebe 2022-07-14 thomas
1247 56324ebe 2022-07-14 thomas error = got_gotweb_dupfd(&c->priv_fd[BLOB_FD_1], &fd);
1248 56324ebe 2022-07-14 thomas if (error)
1249 56324ebe 2022-07-14 thomas goto done;
1250 56324ebe 2022-07-14 thomas
1251 56324ebe 2022-07-14 thomas error = got_object_open_as_blob(&blob, repo, commit_id, BUF, fd);
1252 56324ebe 2022-07-14 thomas if (error)
1253 56324ebe 2022-07-14 thomas goto done;
1254 56324ebe 2022-07-14 thomas hdrlen = got_object_blob_get_hdrlen(blob);
1255 56324ebe 2022-07-14 thomas do {
1256 56324ebe 2022-07-14 thomas error = got_object_blob_read_block(&len, blob);
1257 56324ebe 2022-07-14 thomas if (error)
1258 56324ebe 2022-07-14 thomas goto done;
1259 56324ebe 2022-07-14 thomas buf = got_object_blob_get_read_buf(blob);
1260 56324ebe 2022-07-14 thomas
1261 56324ebe 2022-07-14 thomas /*
1262 56324ebe 2022-07-14 thomas * Skip blob object header first time around,
1263 56324ebe 2022-07-14 thomas * which also contains a zero byte.
1264 56324ebe 2022-07-14 thomas */
1265 56324ebe 2022-07-14 thomas buf += hdrlen;
1266 56324ebe 2022-07-14 thomas if (set_mime == 0) {
1267 56324ebe 2022-07-14 thomas if (isbinary(buf, len - hdrlen)) {
1268 56324ebe 2022-07-14 thomas error = gotweb_render_content_type_file(c,
1269 56324ebe 2022-07-14 thomas "application/octet-stream",
1270 56324ebe 2022-07-14 thomas qs->file);
1271 56324ebe 2022-07-14 thomas if (error) {
1272 56324ebe 2022-07-14 thomas log_warnx("%s: %s", __func__,
1273 56324ebe 2022-07-14 thomas error->msg);
1274 56324ebe 2022-07-14 thomas goto done;
1275 56324ebe 2022-07-14 thomas }
1276 56324ebe 2022-07-14 thomas type = 0;
1277 56324ebe 2022-07-14 thomas } else {
1278 56324ebe 2022-07-14 thomas error = gotweb_render_content_type(c,
1279 56324ebe 2022-07-14 thomas "text/text");
1280 56324ebe 2022-07-14 thomas if (error) {
1281 56324ebe 2022-07-14 thomas log_warnx("%s: %s", __func__,
1282 56324ebe 2022-07-14 thomas error->msg);
1283 56324ebe 2022-07-14 thomas goto done;
1284 56324ebe 2022-07-14 thomas }
1285 56324ebe 2022-07-14 thomas type = 1;
1286 56324ebe 2022-07-14 thomas }
1287 56324ebe 2022-07-14 thomas }
1288 56324ebe 2022-07-14 thomas set_mime = 1;
1289 56324ebe 2022-07-14 thomas if (type) {
1290 56324ebe 2022-07-14 thomas buf_output = calloc(len - hdrlen + 1,
1291 56324ebe 2022-07-14 thomas sizeof(*buf_output));
1292 56324ebe 2022-07-14 thomas if (buf_output == NULL) {
1293 56324ebe 2022-07-14 thomas error = got_error_from_errno("calloc");
1294 56324ebe 2022-07-14 thomas goto done;
1295 56324ebe 2022-07-14 thomas }
1296 56324ebe 2022-07-14 thomas memcpy(buf_output, buf, len - hdrlen);
1297 56324ebe 2022-07-14 thomas fcgi_gen_response(c, buf_output);
1298 56324ebe 2022-07-14 thomas free(buf_output);
1299 56324ebe 2022-07-14 thomas buf_output = NULL;
1300 56324ebe 2022-07-14 thomas } else
1301 56324ebe 2022-07-14 thomas fcgi_gen_binary_response(c, buf, len - hdrlen);
1302 56324ebe 2022-07-14 thomas
1303 56324ebe 2022-07-14 thomas hdrlen = 0;
1304 56324ebe 2022-07-14 thomas } while (len != 0);
1305 56324ebe 2022-07-14 thomas done:
1306 56324ebe 2022-07-14 thomas if (commit)
1307 56324ebe 2022-07-14 thomas got_object_commit_close(commit);
1308 56324ebe 2022-07-14 thomas if (fd != -1 && close(fd) == -1 && error == NULL)
1309 56324ebe 2022-07-14 thomas error = got_error_from_errno("close");
1310 56324ebe 2022-07-14 thomas if (blob)
1311 56324ebe 2022-07-14 thomas got_object_blob_close(blob);
1312 56324ebe 2022-07-14 thomas free(buf_output);
1313 56324ebe 2022-07-14 thomas free(in_repo_path);
1314 56324ebe 2022-07-14 thomas free(commit_id);
1315 56324ebe 2022-07-14 thomas free(path);
1316 56324ebe 2022-07-14 thomas return error;
1317 56324ebe 2022-07-14 thomas }
1318 56324ebe 2022-07-14 thomas
1319 56324ebe 2022-07-14 thomas struct blame_line {
1320 56324ebe 2022-07-14 thomas int annotated;
1321 56324ebe 2022-07-14 thomas char *id_str;
1322 56324ebe 2022-07-14 thomas char *committer;
1323 56324ebe 2022-07-14 thomas char datebuf[11]; /* YYYY-MM-DD + NUL */
1324 56324ebe 2022-07-14 thomas };
1325 56324ebe 2022-07-14 thomas
1326 56324ebe 2022-07-14 thomas struct blame_cb_args {
1327 56324ebe 2022-07-14 thomas struct blame_line *lines;
1328 56324ebe 2022-07-14 thomas int nlines;
1329 56324ebe 2022-07-14 thomas int nlines_prec;
1330 56324ebe 2022-07-14 thomas int lineno_cur;
1331 56324ebe 2022-07-14 thomas off_t *line_offsets;
1332 56324ebe 2022-07-14 thomas FILE *f;
1333 56324ebe 2022-07-14 thomas struct got_repository *repo;
1334 56324ebe 2022-07-14 thomas struct request *c;
1335 56324ebe 2022-07-14 thomas };
1336 56324ebe 2022-07-14 thomas
1337 56324ebe 2022-07-14 thomas static const struct got_error *
1338 56324ebe 2022-07-14 thomas got_gotweb_blame_cb(void *arg, int nlines, int lineno,
1339 56324ebe 2022-07-14 thomas struct got_commit_object *commit, struct got_object_id *id)
1340 56324ebe 2022-07-14 thomas {
1341 56324ebe 2022-07-14 thomas const struct got_error *err = NULL;
1342 56324ebe 2022-07-14 thomas struct blame_cb_args *a = arg;
1343 56324ebe 2022-07-14 thomas struct blame_line *bline;
1344 56324ebe 2022-07-14 thomas struct request *c = a->c;
1345 56324ebe 2022-07-14 thomas struct transport *t = c->t;
1346 56324ebe 2022-07-14 thomas struct querystring *qs = t->qs;
1347 56324ebe 2022-07-14 thomas struct repo_dir *repo_dir = t->repo_dir;
1348 56324ebe 2022-07-14 thomas char *line = NULL, *eline = NULL;
1349 56324ebe 2022-07-14 thomas size_t linesize = 0;
1350 56324ebe 2022-07-14 thomas off_t offset;
1351 56324ebe 2022-07-14 thomas struct tm tm;
1352 56324ebe 2022-07-14 thomas time_t committer_time;
1353 56324ebe 2022-07-14 thomas
1354 56324ebe 2022-07-14 thomas if (nlines != a->nlines ||
1355 56324ebe 2022-07-14 thomas (lineno != -1 && lineno < 1) || lineno > a->nlines)
1356 56324ebe 2022-07-14 thomas return got_error(GOT_ERR_RANGE);
1357 56324ebe 2022-07-14 thomas
1358 56324ebe 2022-07-14 thomas if (lineno == -1)
1359 56324ebe 2022-07-14 thomas return NULL; /* no change in this commit */
1360 56324ebe 2022-07-14 thomas
1361 56324ebe 2022-07-14 thomas /* Annotate this line. */
1362 56324ebe 2022-07-14 thomas bline = &a->lines[lineno - 1];
1363 56324ebe 2022-07-14 thomas if (bline->annotated)
1364 56324ebe 2022-07-14 thomas return NULL;
1365 56324ebe 2022-07-14 thomas err = got_object_id_str(&bline->id_str, id);
1366 56324ebe 2022-07-14 thomas if (err)
1367 56324ebe 2022-07-14 thomas return err;
1368 56324ebe 2022-07-14 thomas
1369 56324ebe 2022-07-14 thomas bline->committer = strdup(got_object_commit_get_committer(commit));
1370 56324ebe 2022-07-14 thomas if (bline->committer == NULL) {
1371 56324ebe 2022-07-14 thomas err = got_error_from_errno("strdup");
1372 56324ebe 2022-07-14 thomas goto done;
1373 56324ebe 2022-07-14 thomas }
1374 56324ebe 2022-07-14 thomas
1375 56324ebe 2022-07-14 thomas committer_time = got_object_commit_get_committer_time(commit);
1376 56324ebe 2022-07-14 thomas if (gmtime_r(&committer_time, &tm) == NULL)
1377 56324ebe 2022-07-14 thomas return got_error_from_errno("gmtime_r");
1378 56324ebe 2022-07-14 thomas if (strftime(bline->datebuf, sizeof(bline->datebuf), "%G-%m-%d",
1379 56324ebe 2022-07-14 thomas &tm) == 0) {
1380 56324ebe 2022-07-14 thomas err = got_error(GOT_ERR_NO_SPACE);
1381 56324ebe 2022-07-14 thomas goto done;
1382 56324ebe 2022-07-14 thomas }
1383 56324ebe 2022-07-14 thomas bline->annotated = 1;
1384 56324ebe 2022-07-14 thomas
1385 56324ebe 2022-07-14 thomas /* Print lines annotated so far. */
1386 56324ebe 2022-07-14 thomas bline = &a->lines[a->lineno_cur - 1];
1387 56324ebe 2022-07-14 thomas if (!bline->annotated)
1388 56324ebe 2022-07-14 thomas goto done;
1389 56324ebe 2022-07-14 thomas
1390 56324ebe 2022-07-14 thomas offset = a->line_offsets[a->lineno_cur - 1];
1391 56324ebe 2022-07-14 thomas if (fseeko(a->f, offset, SEEK_SET) == -1) {
1392 56324ebe 2022-07-14 thomas err = got_error_from_errno("fseeko");
1393 56324ebe 2022-07-14 thomas goto done;
1394 56324ebe 2022-07-14 thomas }
1395 56324ebe 2022-07-14 thomas
1396 56324ebe 2022-07-14 thomas while (bline->annotated) {
1397 56324ebe 2022-07-14 thomas int out_buff_size = 100;
1398 56324ebe 2022-07-14 thomas char *smallerthan, *at, *nl, *committer;
1399 56324ebe 2022-07-14 thomas char out_buff[out_buff_size];
1400 56324ebe 2022-07-14 thomas size_t len;
1401 56324ebe 2022-07-14 thomas
1402 56324ebe 2022-07-14 thomas if (getline(&line, &linesize, a->f) == -1) {
1403 56324ebe 2022-07-14 thomas if (ferror(a->f))
1404 56324ebe 2022-07-14 thomas err = got_error_from_errno("getline");
1405 56324ebe 2022-07-14 thomas break;
1406 56324ebe 2022-07-14 thomas }
1407 56324ebe 2022-07-14 thomas
1408 56324ebe 2022-07-14 thomas committer = bline->committer;
1409 56324ebe 2022-07-14 thomas smallerthan = strchr(committer, '<');
1410 56324ebe 2022-07-14 thomas if (smallerthan && smallerthan[1] != '\0')
1411 56324ebe 2022-07-14 thomas committer = smallerthan + 1;
1412 56324ebe 2022-07-14 thomas at = strchr(committer, '@');
1413 56324ebe 2022-07-14 thomas if (at)
1414 56324ebe 2022-07-14 thomas *at = '\0';
1415 56324ebe 2022-07-14 thomas len = strlen(committer);
1416 56324ebe 2022-07-14 thomas if (len >= 9)
1417 56324ebe 2022-07-14 thomas committer[8] = '\0';
1418 56324ebe 2022-07-14 thomas
1419 56324ebe 2022-07-14 thomas nl = strchr(line, '\n');
1420 56324ebe 2022-07-14 thomas if (nl)
1421 56324ebe 2022-07-14 thomas *nl = '\0';
1422 56324ebe 2022-07-14 thomas
1423 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<div id='blame_wrapper'>") == -1)
1424 56324ebe 2022-07-14 thomas goto done;
1425 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<div id='blame_number'>") == -1)
1426 56324ebe 2022-07-14 thomas goto done;
1427 56324ebe 2022-07-14 thomas if (snprintf(out_buff, strlen(out_buff), "%.*d", a->nlines_prec,
1428 56324ebe 2022-07-14 thomas a->lineno_cur) < 0)
1429 56324ebe 2022-07-14 thomas goto done;
1430 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, out_buff) == -1)
1431 56324ebe 2022-07-14 thomas goto done;
1432 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>") == -1)
1433 56324ebe 2022-07-14 thomas goto done;
1434 56324ebe 2022-07-14 thomas
1435 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<div id='blame_hash'>") == -1)
1436 56324ebe 2022-07-14 thomas goto done;
1437 56324ebe 2022-07-14 thomas
1438 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
1439 56324ebe 2022-07-14 thomas goto done;
1440 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, qs->index_page_str) == -1)
1441 56324ebe 2022-07-14 thomas goto done;
1442 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&path=") == -1)
1443 56324ebe 2022-07-14 thomas goto done;
1444 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, repo_dir->name) == -1)
1445 56324ebe 2022-07-14 thomas goto done;
1446 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "&action=diff&commit=") == -1)
1447 56324ebe 2022-07-14 thomas goto done;
1448 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, bline->id_str) == -1)
1449 56324ebe 2022-07-14 thomas goto done;
1450 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "'>") == -1)
1451 56324ebe 2022-07-14 thomas goto done;
1452 56324ebe 2022-07-14 thomas if (snprintf(out_buff, 10, "%.8s", bline->id_str) < 0)
1453 56324ebe 2022-07-14 thomas goto done;
1454 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, out_buff) == -1)
1455 56324ebe 2022-07-14 thomas goto done;
1456 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</a></div>") == -1)
1457 56324ebe 2022-07-14 thomas goto done;
1458 56324ebe 2022-07-14 thomas
1459 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<div id='blame_date'>") == -1)
1460 56324ebe 2022-07-14 thomas goto done;
1461 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, bline->datebuf) == -1)
1462 56324ebe 2022-07-14 thomas goto done;
1463 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>") == -1)
1464 56324ebe 2022-07-14 thomas goto done;
1465 56324ebe 2022-07-14 thomas
1466 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<div id='blame_author'>") == -1)
1467 56324ebe 2022-07-14 thomas goto done;
1468 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, committer) == -1)
1469 56324ebe 2022-07-14 thomas goto done;
1470 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>") == -1)
1471 56324ebe 2022-07-14 thomas goto done;
1472 56324ebe 2022-07-14 thomas
1473 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<div id='blame_code'>") == -1)
1474 56324ebe 2022-07-14 thomas goto done;
1475 56324ebe 2022-07-14 thomas err = gotweb_escape_html(&eline, line);
1476 56324ebe 2022-07-14 thomas if (err)
1477 56324ebe 2022-07-14 thomas goto done;
1478 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, eline) == -1)
1479 56324ebe 2022-07-14 thomas goto done;
1480 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>") == -1)
1481 56324ebe 2022-07-14 thomas goto done;
1482 56324ebe 2022-07-14 thomas
1483 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>") == -1)
1484 56324ebe 2022-07-14 thomas goto done;
1485 56324ebe 2022-07-14 thomas a->lineno_cur++;
1486 56324ebe 2022-07-14 thomas bline = &a->lines[a->lineno_cur - 1];
1487 56324ebe 2022-07-14 thomas }
1488 56324ebe 2022-07-14 thomas done:
1489 56324ebe 2022-07-14 thomas free(line);
1490 56324ebe 2022-07-14 thomas free(eline);
1491 56324ebe 2022-07-14 thomas return err;
1492 56324ebe 2022-07-14 thomas }
1493 56324ebe 2022-07-14 thomas
1494 56324ebe 2022-07-14 thomas const struct got_error *
1495 56324ebe 2022-07-14 thomas got_output_file_blame(struct request *c)
1496 56324ebe 2022-07-14 thomas {
1497 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
1498 56324ebe 2022-07-14 thomas struct transport *t = c->t;
1499 56324ebe 2022-07-14 thomas struct got_repository *repo = t->repo;
1500 56324ebe 2022-07-14 thomas struct querystring *qs = c->t->qs;
1501 56324ebe 2022-07-14 thomas struct got_object_id *obj_id = NULL, *commit_id = NULL;
1502 56324ebe 2022-07-14 thomas struct got_commit_object *commit = NULL;
1503 56324ebe 2022-07-14 thomas struct got_reflist_head refs;
1504 56324ebe 2022-07-14 thomas struct got_blob_object *blob = NULL;
1505 56324ebe 2022-07-14 thomas char *path = NULL, *in_repo_path = NULL;
1506 56324ebe 2022-07-14 thomas struct blame_cb_args bca;
1507 56324ebe 2022-07-14 thomas int i, obj_type, fd1 = -1, fd2 = -1, fd3 = -1, fd4 = -1, fd5 = -1;
1508 56324ebe 2022-07-14 thomas int fd6 = -1;
1509 56324ebe 2022-07-14 thomas off_t filesize;
1510 56324ebe 2022-07-14 thomas FILE *f1 = NULL, *f2 = NULL;
1511 56324ebe 2022-07-14 thomas
1512 56324ebe 2022-07-14 thomas TAILQ_INIT(&refs);
1513 56324ebe 2022-07-14 thomas bca.f = NULL;
1514 56324ebe 2022-07-14 thomas bca.lines = NULL;
1515 56324ebe 2022-07-14 thomas
1516 56324ebe 2022-07-14 thomas if (asprintf(&path, "%s%s%s", qs->folder ? qs->folder : "",
1517 56324ebe 2022-07-14 thomas qs->folder ? "/" : "", qs->file) == -1) {
1518 56324ebe 2022-07-14 thomas error = got_error_from_errno("asprintf");
1519 56324ebe 2022-07-14 thomas goto done;
1520 56324ebe 2022-07-14 thomas }
1521 56324ebe 2022-07-14 thomas
1522 56324ebe 2022-07-14 thomas error = got_repo_map_path(&in_repo_path, repo, path);
1523 56324ebe 2022-07-14 thomas if (error)
1524 56324ebe 2022-07-14 thomas goto done;
1525 56324ebe 2022-07-14 thomas
1526 56324ebe 2022-07-14 thomas error = got_repo_match_object_id(&commit_id, NULL, qs->commit,
1527 56324ebe 2022-07-14 thomas GOT_OBJ_TYPE_COMMIT, &refs, repo);
1528 56324ebe 2022-07-14 thomas if (error)
1529 56324ebe 2022-07-14 thomas goto done;
1530 56324ebe 2022-07-14 thomas
1531 56324ebe 2022-07-14 thomas error = got_object_open_as_commit(&commit, repo, commit_id);
1532 56324ebe 2022-07-14 thomas if (error)
1533 56324ebe 2022-07-14 thomas goto done;
1534 56324ebe 2022-07-14 thomas
1535 56324ebe 2022-07-14 thomas error = got_object_id_by_path(&obj_id, repo, commit, in_repo_path);
1536 56324ebe 2022-07-14 thomas if (error)
1537 56324ebe 2022-07-14 thomas goto done;
1538 56324ebe 2022-07-14 thomas
1539 56324ebe 2022-07-14 thomas if (commit_id == NULL) {
1540 56324ebe 2022-07-14 thomas error = got_error(GOT_ERR_NO_OBJ);
1541 56324ebe 2022-07-14 thomas goto done;
1542 56324ebe 2022-07-14 thomas }
1543 56324ebe 2022-07-14 thomas
1544 56324ebe 2022-07-14 thomas error = got_object_get_type(&obj_type, repo, obj_id);
1545 56324ebe 2022-07-14 thomas if (error)
1546 56324ebe 2022-07-14 thomas goto done;
1547 56324ebe 2022-07-14 thomas
1548 56324ebe 2022-07-14 thomas if (obj_type != GOT_OBJ_TYPE_BLOB) {
1549 56324ebe 2022-07-14 thomas error = got_error(GOT_ERR_OBJ_TYPE);
1550 56324ebe 2022-07-14 thomas goto done;
1551 56324ebe 2022-07-14 thomas }
1552 56324ebe 2022-07-14 thomas
1553 56324ebe 2022-07-14 thomas error = got_gotweb_openfile(&bca.f, &c->priv_fd[BLAME_FD_1], &fd1);
1554 56324ebe 2022-07-14 thomas if (error)
1555 56324ebe 2022-07-14 thomas goto done;
1556 56324ebe 2022-07-14 thomas
1557 56324ebe 2022-07-14 thomas error = got_gotweb_dupfd(&c->priv_fd[BLAME_FD_2], &fd2);
1558 56324ebe 2022-07-14 thomas if (error)
1559 56324ebe 2022-07-14 thomas goto done;
1560 56324ebe 2022-07-14 thomas
1561 56324ebe 2022-07-14 thomas error = got_object_open_as_blob(&blob, repo, obj_id, BUF, fd2);
1562 56324ebe 2022-07-14 thomas if (error)
1563 56324ebe 2022-07-14 thomas goto done;
1564 56324ebe 2022-07-14 thomas
1565 56324ebe 2022-07-14 thomas error = got_object_blob_dump_to_file(&filesize, &bca.nlines,
1566 56324ebe 2022-07-14 thomas &bca.line_offsets, bca.f, blob);
1567 56324ebe 2022-07-14 thomas if (error || bca.nlines == 0)
1568 56324ebe 2022-07-14 thomas goto done;
1569 56324ebe 2022-07-14 thomas
1570 56324ebe 2022-07-14 thomas /* Don't include \n at EOF in the blame line count. */
1571 56324ebe 2022-07-14 thomas if (bca.line_offsets[bca.nlines - 1] == filesize)
1572 56324ebe 2022-07-14 thomas bca.nlines--;
1573 56324ebe 2022-07-14 thomas
1574 56324ebe 2022-07-14 thomas bca.lines = calloc(bca.nlines, sizeof(*bca.lines));
1575 56324ebe 2022-07-14 thomas if (bca.lines == NULL) {
1576 56324ebe 2022-07-14 thomas error = got_error_from_errno("calloc");
1577 56324ebe 2022-07-14 thomas goto done;
1578 56324ebe 2022-07-14 thomas }
1579 56324ebe 2022-07-14 thomas bca.lineno_cur = 1;
1580 56324ebe 2022-07-14 thomas bca.nlines_prec = 0;
1581 56324ebe 2022-07-14 thomas i = bca.nlines;
1582 56324ebe 2022-07-14 thomas while (i > 0) {
1583 56324ebe 2022-07-14 thomas i /= 10;
1584 56324ebe 2022-07-14 thomas bca.nlines_prec++;
1585 56324ebe 2022-07-14 thomas }
1586 56324ebe 2022-07-14 thomas bca.repo = repo;
1587 56324ebe 2022-07-14 thomas bca.c = c;
1588 56324ebe 2022-07-14 thomas
1589 56324ebe 2022-07-14 thomas error = got_gotweb_dupfd(&c->priv_fd[BLAME_FD_3], &fd3);
1590 56324ebe 2022-07-14 thomas if (error)
1591 56324ebe 2022-07-14 thomas goto done;
1592 56324ebe 2022-07-14 thomas
1593 56324ebe 2022-07-14 thomas error = got_gotweb_dupfd(&c->priv_fd[BLAME_FD_4], &fd4);
1594 56324ebe 2022-07-14 thomas if (error)
1595 56324ebe 2022-07-14 thomas goto done;
1596 56324ebe 2022-07-14 thomas
1597 56324ebe 2022-07-14 thomas error = got_gotweb_openfile(&f1, &c->priv_fd[BLAME_FD_5], &fd5);
1598 56324ebe 2022-07-14 thomas if (error)
1599 56324ebe 2022-07-14 thomas goto done;
1600 56324ebe 2022-07-14 thomas
1601 56324ebe 2022-07-14 thomas error = got_gotweb_openfile(&f2, &c->priv_fd[BLAME_FD_6], &fd6);
1602 56324ebe 2022-07-14 thomas if (error)
1603 56324ebe 2022-07-14 thomas goto done;
1604 56324ebe 2022-07-14 thomas
1605 56324ebe 2022-07-14 thomas error = got_blame(in_repo_path, commit_id, repo,
1606 56324ebe 2022-07-14 thomas GOT_DIFF_ALGORITHM_MYERS, got_gotweb_blame_cb, &bca, NULL, NULL,
1607 56324ebe 2022-07-14 thomas fd3, fd4, f1, f2);
1608 56324ebe 2022-07-14 thomas
1609 56324ebe 2022-07-14 thomas if (blob) {
1610 56324ebe 2022-07-14 thomas free(bca.line_offsets);
1611 56324ebe 2022-07-14 thomas for (i = 0; i < bca.nlines; i++) {
1612 56324ebe 2022-07-14 thomas struct blame_line *bline = &bca.lines[i];
1613 56324ebe 2022-07-14 thomas free(bline->id_str);
1614 56324ebe 2022-07-14 thomas free(bline->committer);
1615 56324ebe 2022-07-14 thomas }
1616 56324ebe 2022-07-14 thomas }
1617 56324ebe 2022-07-14 thomas done:
1618 56324ebe 2022-07-14 thomas free(bca.lines);
1619 56324ebe 2022-07-14 thomas if (fd2 != -1 && close(fd2) == -1 && error == NULL)
1620 56324ebe 2022-07-14 thomas error = got_error_from_errno("close");
1621 56324ebe 2022-07-14 thomas if (fd3 != -1 && close(fd3) == -1 && error == NULL)
1622 56324ebe 2022-07-14 thomas error = got_error_from_errno("close");
1623 56324ebe 2022-07-14 thomas if (fd4 != -1 && close(fd4) == -1 && error == NULL)
1624 56324ebe 2022-07-14 thomas error = got_error_from_errno("close");
1625 56324ebe 2022-07-14 thomas if (bca.f) {
1626 56324ebe 2022-07-14 thomas const struct got_error *bca_err =
1627 56324ebe 2022-07-14 thomas got_gotweb_flushfile(bca.f, fd1);
1628 56324ebe 2022-07-14 thomas if (error == NULL)
1629 56324ebe 2022-07-14 thomas error = bca_err;
1630 56324ebe 2022-07-14 thomas }
1631 56324ebe 2022-07-14 thomas if (f1) {
1632 56324ebe 2022-07-14 thomas const struct got_error *f1_err =
1633 56324ebe 2022-07-14 thomas got_gotweb_flushfile(f1, fd5);
1634 56324ebe 2022-07-14 thomas if (error == NULL)
1635 56324ebe 2022-07-14 thomas error = f1_err;
1636 56324ebe 2022-07-14 thomas }
1637 56324ebe 2022-07-14 thomas if (f2) {
1638 56324ebe 2022-07-14 thomas const struct got_error *f2_err =
1639 56324ebe 2022-07-14 thomas got_gotweb_flushfile(f2, fd6);
1640 56324ebe 2022-07-14 thomas if (error == NULL)
1641 56324ebe 2022-07-14 thomas error = f2_err;
1642 56324ebe 2022-07-14 thomas }
1643 56324ebe 2022-07-14 thomas if (commit)
1644 56324ebe 2022-07-14 thomas got_object_commit_close(commit);
1645 56324ebe 2022-07-14 thomas if (blob)
1646 56324ebe 2022-07-14 thomas got_object_blob_close(blob);
1647 56324ebe 2022-07-14 thomas free(in_repo_path);
1648 56324ebe 2022-07-14 thomas free(commit_id);
1649 56324ebe 2022-07-14 thomas free(path);
1650 56324ebe 2022-07-14 thomas return error;
1651 56324ebe 2022-07-14 thomas }
1652 56324ebe 2022-07-14 thomas
1653 56324ebe 2022-07-14 thomas const struct got_error *
1654 56324ebe 2022-07-14 thomas got_output_repo_diff(struct request *c)
1655 56324ebe 2022-07-14 thomas {
1656 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
1657 56324ebe 2022-07-14 thomas struct transport *t = c->t;
1658 56324ebe 2022-07-14 thomas struct got_repository *repo = t->repo;
1659 56324ebe 2022-07-14 thomas struct repo_commit *rc = NULL;
1660 56324ebe 2022-07-14 thomas struct got_object_id *id1 = NULL, *id2 = NULL;
1661 56324ebe 2022-07-14 thomas struct got_reflist_head refs;
1662 56324ebe 2022-07-14 thomas FILE *f1 = NULL, *f2 = NULL, *f3 = NULL;
1663 56324ebe 2022-07-14 thomas char *label1 = NULL, *label2 = NULL, *line = NULL;
1664 56324ebe 2022-07-14 thomas char *newline, *eline = NULL, *color = NULL;
1665 56324ebe 2022-07-14 thomas int obj_type, fd1, fd2, fd3, fd4 = -1, fd5 = -1;
1666 56324ebe 2022-07-14 thomas size_t linesize = 0;
1667 56324ebe 2022-07-14 thomas ssize_t linelen;
1668 56324ebe 2022-07-14 thomas int wrlen = 0;
1669 56324ebe 2022-07-14 thomas
1670 56324ebe 2022-07-14 thomas TAILQ_INIT(&refs);
1671 56324ebe 2022-07-14 thomas
1672 56324ebe 2022-07-14 thomas error = got_gotweb_openfile(&f1, &c->priv_fd[DIFF_FD_1], &fd1);
1673 56324ebe 2022-07-14 thomas if (error)
1674 56324ebe 2022-07-14 thomas return error;
1675 56324ebe 2022-07-14 thomas
1676 56324ebe 2022-07-14 thomas error = got_gotweb_openfile(&f2, &c->priv_fd[DIFF_FD_2], &fd2);
1677 56324ebe 2022-07-14 thomas if (error)
1678 56324ebe 2022-07-14 thomas return error;
1679 56324ebe 2022-07-14 thomas
1680 56324ebe 2022-07-14 thomas error = got_gotweb_openfile(&f3, &c->priv_fd[DIFF_FD_3], &fd3);
1681 56324ebe 2022-07-14 thomas if (error)
1682 56324ebe 2022-07-14 thomas return error;
1683 56324ebe 2022-07-14 thomas
1684 56324ebe 2022-07-14 thomas rc = TAILQ_FIRST(&t->repo_commits);
1685 56324ebe 2022-07-14 thomas
1686 56324ebe 2022-07-14 thomas if (rc->parent_id != NULL &&
1687 56324ebe 2022-07-14 thomas strncmp(rc->parent_id, "/dev/null", 9) != 0) {
1688 56324ebe 2022-07-14 thomas error = got_repo_match_object_id(&id1, &label1,
1689 56324ebe 2022-07-14 thomas rc->parent_id, GOT_OBJ_TYPE_ANY,
1690 56324ebe 2022-07-14 thomas &refs, repo);
1691 56324ebe 2022-07-14 thomas if (error)
1692 56324ebe 2022-07-14 thomas goto done;
1693 56324ebe 2022-07-14 thomas }
1694 56324ebe 2022-07-14 thomas
1695 56324ebe 2022-07-14 thomas error = got_repo_match_object_id(&id2, &label2, rc->commit_id,
1696 56324ebe 2022-07-14 thomas GOT_OBJ_TYPE_ANY, &refs, repo);
1697 56324ebe 2022-07-14 thomas if (error)
1698 56324ebe 2022-07-14 thomas goto done;
1699 56324ebe 2022-07-14 thomas
1700 56324ebe 2022-07-14 thomas error = got_object_get_type(&obj_type, repo, id2);
1701 56324ebe 2022-07-14 thomas if (error)
1702 56324ebe 2022-07-14 thomas goto done;
1703 56324ebe 2022-07-14 thomas
1704 56324ebe 2022-07-14 thomas error = got_gotweb_dupfd(&c->priv_fd[DIFF_FD_4], &fd4);
1705 56324ebe 2022-07-14 thomas if (error)
1706 56324ebe 2022-07-14 thomas goto done;
1707 56324ebe 2022-07-14 thomas
1708 56324ebe 2022-07-14 thomas error = got_gotweb_dupfd(&c->priv_fd[DIFF_FD_5], &fd5);
1709 56324ebe 2022-07-14 thomas if (error)
1710 56324ebe 2022-07-14 thomas goto done;
1711 56324ebe 2022-07-14 thomas
1712 56324ebe 2022-07-14 thomas switch (obj_type) {
1713 56324ebe 2022-07-14 thomas case GOT_OBJ_TYPE_BLOB:
1714 56324ebe 2022-07-14 thomas error = got_diff_objects_as_blobs(NULL, NULL, f1, f2, fd4, fd5,
1715 56324ebe 2022-07-14 thomas id1, id2, NULL, NULL, GOT_DIFF_ALGORITHM_MYERS, 3, 0, 0,
1716 56324ebe 2022-07-14 thomas repo, f3);
1717 56324ebe 2022-07-14 thomas break;
1718 56324ebe 2022-07-14 thomas case GOT_OBJ_TYPE_TREE:
1719 56324ebe 2022-07-14 thomas error = got_diff_objects_as_trees(NULL, NULL, f1, f2, fd4, fd5,
1720 56324ebe 2022-07-14 thomas id1, id2, NULL, "", "", GOT_DIFF_ALGORITHM_MYERS, 3, 0, 0,
1721 56324ebe 2022-07-14 thomas repo, f3);
1722 56324ebe 2022-07-14 thomas break;
1723 56324ebe 2022-07-14 thomas case GOT_OBJ_TYPE_COMMIT:
1724 56324ebe 2022-07-14 thomas error = got_diff_objects_as_commits(NULL, NULL, f1, f2, fd4,
1725 56324ebe 2022-07-14 thomas fd5, id1, id2, NULL, GOT_DIFF_ALGORITHM_MYERS, 3, 0, 0,
1726 56324ebe 2022-07-14 thomas repo, f3);
1727 56324ebe 2022-07-14 thomas break;
1728 56324ebe 2022-07-14 thomas default:
1729 56324ebe 2022-07-14 thomas error = got_error(GOT_ERR_OBJ_TYPE);
1730 56324ebe 2022-07-14 thomas }
1731 56324ebe 2022-07-14 thomas if (error)
1732 56324ebe 2022-07-14 thomas goto done;
1733 56324ebe 2022-07-14 thomas
1734 56324ebe 2022-07-14 thomas if (fseek(f1, 0, SEEK_SET) == -1) {
1735 56324ebe 2022-07-14 thomas error = got_ferror(f1, GOT_ERR_IO);
1736 56324ebe 2022-07-14 thomas goto done;
1737 56324ebe 2022-07-14 thomas }
1738 56324ebe 2022-07-14 thomas
1739 56324ebe 2022-07-14 thomas if (fseek(f2, 0, SEEK_SET) == -1) {
1740 56324ebe 2022-07-14 thomas error = got_ferror(f2, GOT_ERR_IO);
1741 56324ebe 2022-07-14 thomas goto done;
1742 56324ebe 2022-07-14 thomas }
1743 56324ebe 2022-07-14 thomas
1744 56324ebe 2022-07-14 thomas if (fseek(f3, 0, SEEK_SET) == -1) {
1745 56324ebe 2022-07-14 thomas error = got_ferror(f3, GOT_ERR_IO);
1746 56324ebe 2022-07-14 thomas goto done;
1747 56324ebe 2022-07-14 thomas }
1748 56324ebe 2022-07-14 thomas
1749 56324ebe 2022-07-14 thomas while ((linelen = getline(&line, &linesize, f3)) != -1) {
1750 56324ebe 2022-07-14 thomas if (strncmp(line, "-", 1) == 0) {
1751 56324ebe 2022-07-14 thomas color = strdup("diff_minus");
1752 56324ebe 2022-07-14 thomas if (color == NULL) {
1753 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1754 56324ebe 2022-07-14 thomas goto done;
1755 56324ebe 2022-07-14 thomas }
1756 56324ebe 2022-07-14 thomas } else if (strncmp(line, "+", 1) == 0) {
1757 56324ebe 2022-07-14 thomas color = strdup("diff_plus");
1758 56324ebe 2022-07-14 thomas if (color == NULL) {
1759 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1760 56324ebe 2022-07-14 thomas goto done;
1761 56324ebe 2022-07-14 thomas }
1762 56324ebe 2022-07-14 thomas } else if (strncmp(line, "@@", 2) == 0) {
1763 56324ebe 2022-07-14 thomas color = strdup("diff_chunk_header");
1764 56324ebe 2022-07-14 thomas if (color == NULL) {
1765 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1766 56324ebe 2022-07-14 thomas goto done;
1767 56324ebe 2022-07-14 thomas }
1768 56324ebe 2022-07-14 thomas } else if (strncmp(line, "@@", 2) == 0) {
1769 56324ebe 2022-07-14 thomas color = strdup("diff_chunk_header");
1770 56324ebe 2022-07-14 thomas if (color == NULL) {
1771 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1772 56324ebe 2022-07-14 thomas goto done;
1773 56324ebe 2022-07-14 thomas }
1774 56324ebe 2022-07-14 thomas } else if (strncmp(line, "commit +", 8) == 0) {
1775 56324ebe 2022-07-14 thomas color = strdup("diff_meta");
1776 56324ebe 2022-07-14 thomas if (color == NULL) {
1777 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1778 56324ebe 2022-07-14 thomas goto done;
1779 56324ebe 2022-07-14 thomas }
1780 56324ebe 2022-07-14 thomas } else if (strncmp(line, "commit -", 8) == 0) {
1781 56324ebe 2022-07-14 thomas color = strdup("diff_meta");
1782 56324ebe 2022-07-14 thomas if (color == NULL) {
1783 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1784 56324ebe 2022-07-14 thomas goto done;
1785 56324ebe 2022-07-14 thomas }
1786 56324ebe 2022-07-14 thomas } else if (strncmp(line, "blob +", 6) == 0) {
1787 56324ebe 2022-07-14 thomas color = strdup("diff_meta");
1788 56324ebe 2022-07-14 thomas if (color == NULL) {
1789 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1790 56324ebe 2022-07-14 thomas goto done;
1791 56324ebe 2022-07-14 thomas }
1792 56324ebe 2022-07-14 thomas } else if (strncmp(line, "blob -", 6) == 0) {
1793 56324ebe 2022-07-14 thomas color = strdup("diff_meta");
1794 56324ebe 2022-07-14 thomas if (color == NULL) {
1795 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1796 56324ebe 2022-07-14 thomas goto done;
1797 56324ebe 2022-07-14 thomas }
1798 56324ebe 2022-07-14 thomas } else if (strncmp(line, "file +", 6) == 0) {
1799 56324ebe 2022-07-14 thomas color = strdup("diff_meta");
1800 56324ebe 2022-07-14 thomas if (color == NULL) {
1801 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1802 56324ebe 2022-07-14 thomas goto done;
1803 56324ebe 2022-07-14 thomas }
1804 56324ebe 2022-07-14 thomas } else if (strncmp(line, "file -", 6) == 0) {
1805 56324ebe 2022-07-14 thomas color = strdup("diff_meta");
1806 56324ebe 2022-07-14 thomas if (color == NULL) {
1807 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1808 56324ebe 2022-07-14 thomas goto done;
1809 56324ebe 2022-07-14 thomas }
1810 56324ebe 2022-07-14 thomas } else if (strncmp(line, "from:", 5) == 0) {
1811 56324ebe 2022-07-14 thomas color = strdup("diff_author");
1812 56324ebe 2022-07-14 thomas if (color == NULL) {
1813 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1814 56324ebe 2022-07-14 thomas goto done;
1815 56324ebe 2022-07-14 thomas }
1816 56324ebe 2022-07-14 thomas } else if (strncmp(line, "via:", 4) == 0) {
1817 56324ebe 2022-07-14 thomas color = strdup("diff_author");
1818 56324ebe 2022-07-14 thomas if (color == NULL) {
1819 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1820 56324ebe 2022-07-14 thomas goto done;
1821 56324ebe 2022-07-14 thomas }
1822 56324ebe 2022-07-14 thomas } else if (strncmp(line, "date:", 5) == 0) {
1823 56324ebe 2022-07-14 thomas color = strdup("diff_date");
1824 56324ebe 2022-07-14 thomas if (color == NULL) {
1825 56324ebe 2022-07-14 thomas error = got_error_from_errno("strdup");
1826 56324ebe 2022-07-14 thomas goto done;
1827 56324ebe 2022-07-14 thomas }
1828 56324ebe 2022-07-14 thomas }
1829 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "<div id='diff_line' class='") == -1)
1830 56324ebe 2022-07-14 thomas goto done;
1831 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, color ? color : "") == -1)
1832 56324ebe 2022-07-14 thomas goto done;
1833 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "'>") == -1)
1834 56324ebe 2022-07-14 thomas goto done;
1835 56324ebe 2022-07-14 thomas newline = strchr(line, '\n');
1836 56324ebe 2022-07-14 thomas if (newline)
1837 56324ebe 2022-07-14 thomas *newline = '\0';
1838 56324ebe 2022-07-14 thomas
1839 56324ebe 2022-07-14 thomas error = gotweb_escape_html(&eline, line);
1840 56324ebe 2022-07-14 thomas if (error)
1841 56324ebe 2022-07-14 thomas goto done;
1842 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, eline) == -1)
1843 56324ebe 2022-07-14 thomas goto done;
1844 56324ebe 2022-07-14 thomas free(eline);
1845 56324ebe 2022-07-14 thomas eline = NULL;
1846 56324ebe 2022-07-14 thomas
1847 56324ebe 2022-07-14 thomas if (fcgi_gen_response(c, "</div>\n") == -1)
1848 56324ebe 2022-07-14 thomas goto done;
1849 56324ebe 2022-07-14 thomas if (linelen > 0)
1850 56324ebe 2022-07-14 thomas wrlen = wrlen + linelen;
1851 56324ebe 2022-07-14 thomas free(color);
1852 56324ebe 2022-07-14 thomas color = NULL;
1853 56324ebe 2022-07-14 thomas }
1854 56324ebe 2022-07-14 thomas if (linelen == -1 && ferror(f3))
1855 56324ebe 2022-07-14 thomas error = got_error_from_errno("getline");
1856 56324ebe 2022-07-14 thomas done:
1857 56324ebe 2022-07-14 thomas free(color);
1858 56324ebe 2022-07-14 thomas if (fd4 != -1 && close(fd4) == -1 && error == NULL)
1859 56324ebe 2022-07-14 thomas error = got_error_from_errno("close");
1860 56324ebe 2022-07-14 thomas if (fd5 != -1 && close(fd5) == -1 && error == NULL)
1861 56324ebe 2022-07-14 thomas error = got_error_from_errno("close");
1862 56324ebe 2022-07-14 thomas if (f1) {
1863 56324ebe 2022-07-14 thomas const struct got_error *f1_err =
1864 56324ebe 2022-07-14 thomas got_gotweb_flushfile(f1, fd1);
1865 56324ebe 2022-07-14 thomas if (error == NULL)
1866 56324ebe 2022-07-14 thomas error = f1_err;
1867 56324ebe 2022-07-14 thomas }
1868 56324ebe 2022-07-14 thomas if (f2) {
1869 56324ebe 2022-07-14 thomas const struct got_error *f2_err =
1870 56324ebe 2022-07-14 thomas got_gotweb_flushfile(f2, fd2);
1871 56324ebe 2022-07-14 thomas if (error == NULL)
1872 56324ebe 2022-07-14 thomas error = f2_err;
1873 56324ebe 2022-07-14 thomas }
1874 56324ebe 2022-07-14 thomas if (f3) {
1875 56324ebe 2022-07-14 thomas const struct got_error *f3_err =
1876 56324ebe 2022-07-14 thomas got_gotweb_flushfile(f3, fd3);
1877 56324ebe 2022-07-14 thomas if (error == NULL)
1878 56324ebe 2022-07-14 thomas error = f3_err;
1879 56324ebe 2022-07-14 thomas }
1880 56324ebe 2022-07-14 thomas got_ref_list_free(&refs);
1881 56324ebe 2022-07-14 thomas free(line);
1882 56324ebe 2022-07-14 thomas free(eline);
1883 56324ebe 2022-07-14 thomas free(label1);
1884 56324ebe 2022-07-14 thomas free(label2);
1885 56324ebe 2022-07-14 thomas free(id1);
1886 56324ebe 2022-07-14 thomas free(id2);
1887 56324ebe 2022-07-14 thomas return error;
1888 56324ebe 2022-07-14 thomas }
1889 56324ebe 2022-07-14 thomas
1890 56324ebe 2022-07-14 thomas static const struct got_error *
1891 56324ebe 2022-07-14 thomas got_init_repo_commit(struct repo_commit **rc)
1892 56324ebe 2022-07-14 thomas {
1893 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
1894 56324ebe 2022-07-14 thomas
1895 56324ebe 2022-07-14 thomas *rc = calloc(1, sizeof(**rc));
1896 56324ebe 2022-07-14 thomas if (*rc == NULL)
1897 56324ebe 2022-07-14 thomas return got_error_from_errno2("%s: calloc", __func__);
1898 56324ebe 2022-07-14 thomas
1899 56324ebe 2022-07-14 thomas (*rc)->path = NULL;
1900 56324ebe 2022-07-14 thomas (*rc)->refs_str = NULL;
1901 56324ebe 2022-07-14 thomas (*rc)->commit_id = NULL;
1902 56324ebe 2022-07-14 thomas (*rc)->committer = NULL;
1903 56324ebe 2022-07-14 thomas (*rc)->author = NULL;
1904 56324ebe 2022-07-14 thomas (*rc)->parent_id = NULL;
1905 56324ebe 2022-07-14 thomas (*rc)->tree_id = NULL;
1906 56324ebe 2022-07-14 thomas (*rc)->commit_msg = NULL;
1907 56324ebe 2022-07-14 thomas
1908 56324ebe 2022-07-14 thomas return error;
1909 56324ebe 2022-07-14 thomas }
1910 56324ebe 2022-07-14 thomas
1911 56324ebe 2022-07-14 thomas static const struct got_error *
1912 56324ebe 2022-07-14 thomas got_init_repo_tag(struct repo_tag **rt)
1913 56324ebe 2022-07-14 thomas {
1914 56324ebe 2022-07-14 thomas const struct got_error *error = NULL;
1915 56324ebe 2022-07-14 thomas
1916 56324ebe 2022-07-14 thomas *rt = calloc(1, sizeof(**rt));
1917 56324ebe 2022-07-14 thomas if (*rt == NULL)
1918 56324ebe 2022-07-14 thomas return got_error_from_errno2("%s: calloc", __func__);
1919 56324ebe 2022-07-14 thomas
1920 56324ebe 2022-07-14 thomas (*rt)->commit_id = NULL;
1921 56324ebe 2022-07-14 thomas (*rt)->tag_name = NULL;
1922 56324ebe 2022-07-14 thomas (*rt)->tag_commit = NULL;
1923 56324ebe 2022-07-14 thomas (*rt)->commit_msg = NULL;
1924 56324ebe 2022-07-14 thomas (*rt)->tagger = NULL;
1925 56324ebe 2022-07-14 thomas
1926 56324ebe 2022-07-14 thomas return error;
1927 56324ebe 2022-07-14 thomas }