Blame


1 097b408a 2022-10-17 thomas /*
2 097b408a 2022-10-17 thomas * Copyright (c) 2020 Ori Bernstein
3 097b408a 2022-10-17 thomas * Copyright (c) 2021, 2022 Stefan Sperling <stsp@openbsd.org>
4 097b408a 2022-10-17 thomas *
5 097b408a 2022-10-17 thomas * Permission to use, copy, modify, and distribute this software for any
6 097b408a 2022-10-17 thomas * purpose with or without fee is hereby granted, provided that the above
7 097b408a 2022-10-17 thomas * copyright notice and this permission notice appear in all copies.
8 097b408a 2022-10-17 thomas *
9 097b408a 2022-10-17 thomas * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 097b408a 2022-10-17 thomas * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 097b408a 2022-10-17 thomas * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 097b408a 2022-10-17 thomas * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 097b408a 2022-10-17 thomas * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 097b408a 2022-10-17 thomas * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 097b408a 2022-10-17 thomas * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 097b408a 2022-10-17 thomas */
17 097b408a 2022-10-17 thomas
18 097b408a 2022-10-17 thomas #include <sys/types.h>
19 097b408a 2022-10-17 thomas #include <sys/queue.h>
20 097b408a 2022-10-17 thomas #include <sys/uio.h>
21 097b408a 2022-10-17 thomas
22 097b408a 2022-10-17 thomas #include <limits.h>
23 097b408a 2022-10-17 thomas #include <stdio.h>
24 097b408a 2022-10-17 thomas #include <stdint.h>
25 097b408a 2022-10-17 thomas #include <stdlib.h>
26 097b408a 2022-10-17 thomas #include <string.h>
27 abd46894 2022-10-18 thomas #include <time.h>
28 097b408a 2022-10-17 thomas #include <imsg.h>
29 097b408a 2022-10-17 thomas #include <inttypes.h>
30 097b408a 2022-10-17 thomas #include <unistd.h>
31 097b408a 2022-10-17 thomas
32 097b408a 2022-10-17 thomas #include "got_error.h"
33 097b408a 2022-10-17 thomas #include "got_cancel.h"
34 097b408a 2022-10-17 thomas #include "got_object.h"
35 097b408a 2022-10-17 thomas #include "got_reference.h"
36 097b408a 2022-10-17 thomas #include "got_repository_admin.h"
37 097b408a 2022-10-17 thomas #include "got_path.h"
38 097b408a 2022-10-17 thomas
39 097b408a 2022-10-17 thomas #include "got_lib_delta.h"
40 097b408a 2022-10-17 thomas #include "got_lib_object.h"
41 097b408a 2022-10-17 thomas #include "got_lib_object_cache.h"
42 097b408a 2022-10-17 thomas #include "got_lib_object_idset.h"
43 097b408a 2022-10-17 thomas #include "got_lib_privsep.h"
44 abd46894 2022-10-18 thomas #include "got_lib_ratelimit.h"
45 097b408a 2022-10-17 thomas #include "got_lib_pack.h"
46 097b408a 2022-10-17 thomas #include "got_lib_pack_create.h"
47 097b408a 2022-10-17 thomas #include "got_lib_repository.h"
48 097b408a 2022-10-17 thomas
49 097b408a 2022-10-17 thomas struct send_id_arg {
50 097b408a 2022-10-17 thomas struct imsgbuf *ibuf;
51 097b408a 2022-10-17 thomas struct got_object_id *ids[GOT_IMSG_OBJ_ID_LIST_MAX_NIDS];
52 097b408a 2022-10-17 thomas size_t nids;
53 097b408a 2022-10-17 thomas };
54 097b408a 2022-10-17 thomas
55 097b408a 2022-10-17 thomas static const struct got_error *
56 097b408a 2022-10-17 thomas send_id(struct got_object_id *id, void *data, void *arg)
57 097b408a 2022-10-17 thomas {
58 097b408a 2022-10-17 thomas const struct got_error *err = NULL;
59 097b408a 2022-10-17 thomas struct send_id_arg *a = arg;
60 097b408a 2022-10-17 thomas
61 097b408a 2022-10-17 thomas a->ids[a->nids++] = id;
62 097b408a 2022-10-17 thomas
63 097b408a 2022-10-17 thomas if (a->nids >= GOT_IMSG_OBJ_ID_LIST_MAX_NIDS) {
64 097b408a 2022-10-17 thomas err = got_privsep_send_object_idlist(a->ibuf, a->ids, a->nids);
65 097b408a 2022-10-17 thomas if (err)
66 097b408a 2022-10-17 thomas return err;
67 097b408a 2022-10-17 thomas a->nids = 0;
68 097b408a 2022-10-17 thomas }
69 097b408a 2022-10-17 thomas
70 097b408a 2022-10-17 thomas return NULL;
71 097b408a 2022-10-17 thomas }
72 097b408a 2022-10-17 thomas
73 097b408a 2022-10-17 thomas static const struct got_error *
74 097b408a 2022-10-17 thomas send_idset(struct imsgbuf *ibuf, struct got_object_idset *idset)
75 097b408a 2022-10-17 thomas {
76 097b408a 2022-10-17 thomas const struct got_error *err;
77 097b408a 2022-10-17 thomas struct send_id_arg sia;
78 097b408a 2022-10-17 thomas
79 097b408a 2022-10-17 thomas memset(&sia, 0, sizeof(sia));
80 097b408a 2022-10-17 thomas sia.ibuf = ibuf;
81 097b408a 2022-10-17 thomas err = got_object_idset_for_each(idset, send_id, &sia);
82 097b408a 2022-10-17 thomas if (err)
83 097b408a 2022-10-17 thomas return err;
84 097b408a 2022-10-17 thomas
85 097b408a 2022-10-17 thomas if (sia.nids > 0) {
86 097b408a 2022-10-17 thomas err = got_privsep_send_object_idlist(ibuf, sia.ids, sia.nids);
87 097b408a 2022-10-17 thomas if (err)
88 097b408a 2022-10-17 thomas return err;
89 097b408a 2022-10-17 thomas }
90 097b408a 2022-10-17 thomas
91 097b408a 2022-10-17 thomas return got_privsep_send_object_idlist_done(ibuf);
92 097b408a 2022-10-17 thomas }
93 097b408a 2022-10-17 thomas
94 097b408a 2022-10-17 thomas static const struct got_error *
95 097b408a 2022-10-17 thomas recv_reused_delta(struct got_imsg_reused_delta *delta,
96 097b408a 2022-10-17 thomas struct got_object_idset *idset, struct got_pack_metavec *v)
97 097b408a 2022-10-17 thomas {
98 097b408a 2022-10-17 thomas struct got_pack_meta *m, *base;
99 097b408a 2022-10-17 thomas
100 097b408a 2022-10-17 thomas if (delta->delta_offset + delta->delta_size < delta->delta_offset ||
101 097b408a 2022-10-17 thomas delta->delta_offset +
102 097b408a 2022-10-17 thomas delta->delta_compressed_size < delta->delta_offset)
103 097b408a 2022-10-17 thomas return got_error(GOT_ERR_BAD_PACKFILE);
104 097b408a 2022-10-17 thomas
105 097b408a 2022-10-17 thomas m = got_object_idset_get(idset, &delta->id);
106 097b408a 2022-10-17 thomas if (m == NULL)
107 097b408a 2022-10-17 thomas return got_error(GOT_ERR_NO_OBJ);
108 097b408a 2022-10-17 thomas
109 097b408a 2022-10-17 thomas base = got_object_idset_get(idset, &delta->base_id);
110 097b408a 2022-10-17 thomas if (base == NULL)
111 097b408a 2022-10-17 thomas return got_error(GOT_ERR_NO_OBJ);
112 097b408a 2022-10-17 thomas
113 097b408a 2022-10-17 thomas m->delta_len = delta->delta_size;
114 097b408a 2022-10-17 thomas m->delta_compressed_len = delta->delta_compressed_size;
115 097b408a 2022-10-17 thomas m->delta_offset = delta->delta_out_offset;
116 097b408a 2022-10-17 thomas m->prev = base;
117 097b408a 2022-10-17 thomas m->size = delta->result_size;
118 097b408a 2022-10-17 thomas m->reused_delta_offset = delta->delta_offset;
119 097b408a 2022-10-17 thomas m->base_obj_id = got_object_id_dup(&delta->base_id);
120 097b408a 2022-10-17 thomas if (m->base_obj_id == NULL)
121 097b408a 2022-10-17 thomas return got_error_from_errno("got_object_id_dup");
122 097b408a 2022-10-17 thomas
123 097b408a 2022-10-17 thomas return got_pack_add_meta(m, v);
124 097b408a 2022-10-17 thomas }
125 097b408a 2022-10-17 thomas
126 097b408a 2022-10-17 thomas static const struct got_error *
127 097b408a 2022-10-17 thomas prepare_delta_reuse(struct got_pack *pack, struct got_packidx *packidx,
128 097b408a 2022-10-17 thomas int delta_outfd, struct got_repository *repo)
129 097b408a 2022-10-17 thomas {
130 097b408a 2022-10-17 thomas const struct got_error *err = NULL;
131 097b408a 2022-10-17 thomas
132 097b408a 2022-10-17 thomas if (!pack->child_has_delta_outfd) {
133 097b408a 2022-10-17 thomas int outfd_child;
134 097b408a 2022-10-17 thomas outfd_child = dup(delta_outfd);
135 097b408a 2022-10-17 thomas if (outfd_child == -1) {
136 097b408a 2022-10-17 thomas err = got_error_from_errno("dup");
137 097b408a 2022-10-17 thomas goto done;
138 097b408a 2022-10-17 thomas }
139 097b408a 2022-10-17 thomas err = got_privsep_send_raw_delta_outfd(
140 097b408a 2022-10-17 thomas pack->privsep_child->ibuf, outfd_child);
141 097b408a 2022-10-17 thomas if (err)
142 097b408a 2022-10-17 thomas goto done;
143 097b408a 2022-10-17 thomas pack->child_has_delta_outfd = 1;
144 097b408a 2022-10-17 thomas }
145 097b408a 2022-10-17 thomas
146 097b408a 2022-10-17 thomas err = got_privsep_send_delta_reuse_req(pack->privsep_child->ibuf);
147 097b408a 2022-10-17 thomas done:
148 097b408a 2022-10-17 thomas return err;
149 097b408a 2022-10-17 thomas }
150 097b408a 2022-10-17 thomas
151 097b408a 2022-10-17 thomas const struct got_error *
152 097b408a 2022-10-17 thomas got_pack_search_deltas(struct got_pack_metavec *v,
153 097b408a 2022-10-17 thomas struct got_object_idset *idset, int delta_cache_fd,
154 097b408a 2022-10-17 thomas int ncolored, int nfound, int ntrees, int ncommits,
155 097b408a 2022-10-17 thomas struct got_repository *repo,
156 097b408a 2022-10-17 thomas got_pack_progress_cb progress_cb, void *progress_arg,
157 097b408a 2022-10-17 thomas struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg)
158 097b408a 2022-10-17 thomas {
159 097b408a 2022-10-17 thomas const struct got_error *err = NULL;
160 097b408a 2022-10-17 thomas struct got_packidx *packidx;
161 097b408a 2022-10-17 thomas struct got_pack *pack;
162 097b408a 2022-10-17 thomas struct got_imsg_reused_delta deltas[GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS];
163 097b408a 2022-10-17 thomas size_t ndeltas, i;
164 097b408a 2022-10-17 thomas
165 097b408a 2022-10-17 thomas err = got_pack_find_pack_for_reuse(&packidx, repo);
166 097b408a 2022-10-17 thomas if (err)
167 097b408a 2022-10-17 thomas return err;
168 097b408a 2022-10-17 thomas
169 097b408a 2022-10-17 thomas if (packidx == NULL)
170 097b408a 2022-10-17 thomas return NULL;
171 097b408a 2022-10-17 thomas
172 097b408a 2022-10-17 thomas err = got_pack_cache_pack_for_packidx(&pack, packidx, repo);
173 097b408a 2022-10-17 thomas if (err)
174 097b408a 2022-10-17 thomas return err;
175 097b408a 2022-10-17 thomas
176 097b408a 2022-10-17 thomas if (pack->privsep_child == NULL) {
177 097b408a 2022-10-17 thomas err = got_pack_start_privsep_child(pack, packidx);
178 097b408a 2022-10-17 thomas if (err)
179 097b408a 2022-10-17 thomas return err;
180 097b408a 2022-10-17 thomas }
181 097b408a 2022-10-17 thomas
182 097b408a 2022-10-17 thomas err = prepare_delta_reuse(pack, packidx, delta_cache_fd, repo);
183 097b408a 2022-10-17 thomas if (err)
184 097b408a 2022-10-17 thomas return err;
185 097b408a 2022-10-17 thomas
186 097b408a 2022-10-17 thomas err = send_idset(pack->privsep_child->ibuf, idset);
187 097b408a 2022-10-17 thomas if (err)
188 097b408a 2022-10-17 thomas return err;
189 097b408a 2022-10-17 thomas
190 097b408a 2022-10-17 thomas for (;;) {
191 097b408a 2022-10-17 thomas int done = 0;
192 097b408a 2022-10-17 thomas
193 097b408a 2022-10-17 thomas if (cancel_cb) {
194 097b408a 2022-10-17 thomas err = (*cancel_cb)(cancel_arg);
195 097b408a 2022-10-17 thomas if (err)
196 097b408a 2022-10-17 thomas break;
197 097b408a 2022-10-17 thomas }
198 097b408a 2022-10-17 thomas
199 097b408a 2022-10-17 thomas err = got_privsep_recv_reused_deltas(&done, deltas, &ndeltas,
200 097b408a 2022-10-17 thomas pack->privsep_child->ibuf);
201 097b408a 2022-10-17 thomas if (err || done)
202 097b408a 2022-10-17 thomas break;
203 097b408a 2022-10-17 thomas
204 097b408a 2022-10-17 thomas for (i = 0; i < ndeltas; i++) {
205 097b408a 2022-10-17 thomas struct got_imsg_reused_delta *delta = &deltas[i];
206 097b408a 2022-10-17 thomas err = recv_reused_delta(delta, idset, v);
207 097b408a 2022-10-17 thomas if (err)
208 097b408a 2022-10-17 thomas goto done;
209 097b408a 2022-10-17 thomas }
210 097b408a 2022-10-17 thomas
211 097b408a 2022-10-17 thomas err = got_pack_report_progress(progress_cb, progress_arg, rl,
212 097b408a 2022-10-17 thomas ncolored, nfound, ntrees, 0L, ncommits,
213 097b408a 2022-10-17 thomas got_object_idset_num_elements(idset), v->nmeta, 0);
214 097b408a 2022-10-17 thomas if (err)
215 097b408a 2022-10-17 thomas break;
216 097b408a 2022-10-17 thomas }
217 097b408a 2022-10-17 thomas done:
218 097b408a 2022-10-17 thomas return err;
219 097b408a 2022-10-17 thomas }
220 097b408a 2022-10-17 thomas
221 097b408a 2022-10-17 thomas struct recv_painted_commit_arg {
222 097b408a 2022-10-17 thomas int *ncolored;
223 097b408a 2022-10-17 thomas int *nqueued;
224 097b408a 2022-10-17 thomas int *nskip;
225 097b408a 2022-10-17 thomas struct got_object_id_queue *ids;
226 097b408a 2022-10-17 thomas struct got_object_idset *keep;
227 097b408a 2022-10-17 thomas struct got_object_idset *drop;
228 097b408a 2022-10-17 thomas struct got_object_idset *skip;
229 097b408a 2022-10-17 thomas got_pack_progress_cb progress_cb;
230 097b408a 2022-10-17 thomas void *progress_arg;
231 097b408a 2022-10-17 thomas struct got_ratelimit *rl;
232 097b408a 2022-10-17 thomas got_cancel_cb cancel_cb;
233 097b408a 2022-10-17 thomas void *cancel_arg;
234 097b408a 2022-10-17 thomas };
235 097b408a 2022-10-17 thomas
236 097b408a 2022-10-17 thomas static const struct got_error *
237 097b408a 2022-10-17 thomas recv_painted_commit(void *arg, struct got_object_id *id, intptr_t color)
238 097b408a 2022-10-17 thomas {
239 097b408a 2022-10-17 thomas const struct got_error *err = NULL;
240 097b408a 2022-10-17 thomas struct recv_painted_commit_arg *a = arg;
241 097b408a 2022-10-17 thomas struct got_object_qid *qid, *tmp;
242 097b408a 2022-10-17 thomas
243 097b408a 2022-10-17 thomas if (a->cancel_cb) {
244 097b408a 2022-10-17 thomas err = a->cancel_cb(a->cancel_arg);
245 097b408a 2022-10-17 thomas if (err)
246 097b408a 2022-10-17 thomas return err;
247 097b408a 2022-10-17 thomas }
248 097b408a 2022-10-17 thomas
249 097b408a 2022-10-17 thomas switch (color) {
250 097b408a 2022-10-17 thomas case COLOR_KEEP:
251 097b408a 2022-10-17 thomas err = got_object_idset_add(a->keep, id, NULL);
252 097b408a 2022-10-17 thomas if (err)
253 097b408a 2022-10-17 thomas return err;
254 097b408a 2022-10-17 thomas (*a->ncolored)++;
255 097b408a 2022-10-17 thomas break;
256 097b408a 2022-10-17 thomas case COLOR_DROP:
257 097b408a 2022-10-17 thomas err = got_object_idset_add(a->drop, id, NULL);
258 097b408a 2022-10-17 thomas if (err)
259 097b408a 2022-10-17 thomas return err;
260 097b408a 2022-10-17 thomas (*a->ncolored)++;
261 097b408a 2022-10-17 thomas break;
262 097b408a 2022-10-17 thomas case COLOR_SKIP:
263 097b408a 2022-10-17 thomas err = got_object_idset_add(a->skip, id, NULL);
264 097b408a 2022-10-17 thomas if (err)
265 097b408a 2022-10-17 thomas return err;
266 097b408a 2022-10-17 thomas break;
267 097b408a 2022-10-17 thomas default:
268 097b408a 2022-10-17 thomas /* should not happen */
269 097b408a 2022-10-17 thomas return got_error_fmt(GOT_ERR_NOT_IMPL,
270 097b408a 2022-10-17 thomas "%s invalid commit color %"PRIdPTR, __func__, color);
271 097b408a 2022-10-17 thomas }
272 097b408a 2022-10-17 thomas
273 097b408a 2022-10-17 thomas STAILQ_FOREACH_SAFE(qid, a->ids, entry, tmp) {
274 097b408a 2022-10-17 thomas if (got_object_id_cmp(&qid->id, id) != 0)
275 097b408a 2022-10-17 thomas continue;
276 097b408a 2022-10-17 thomas STAILQ_REMOVE(a->ids, qid, got_object_qid, entry);
277 097b408a 2022-10-17 thomas color = (intptr_t)qid->data;
278 097b408a 2022-10-17 thomas got_object_qid_free(qid);
279 097b408a 2022-10-17 thomas (*a->nqueued)--;
280 097b408a 2022-10-17 thomas if (color == COLOR_SKIP)
281 097b408a 2022-10-17 thomas (*a->nskip)--;
282 097b408a 2022-10-17 thomas break;
283 097b408a 2022-10-17 thomas }
284 097b408a 2022-10-17 thomas
285 097b408a 2022-10-17 thomas return got_pack_report_progress(a->progress_cb, a->progress_arg, a->rl,
286 097b408a 2022-10-17 thomas *a->ncolored, 0, 0, 0L, 0, 0, 0, 0);
287 097b408a 2022-10-17 thomas }
288 097b408a 2022-10-17 thomas
289 097b408a 2022-10-17 thomas static const struct got_error *
290 097b408a 2022-10-17 thomas paint_packed_commits(struct got_pack *pack, struct got_object_id *id,
291 097b408a 2022-10-17 thomas int idx, intptr_t color, int *ncolored, int *nqueued, int *nskip,
292 097b408a 2022-10-17 thomas struct got_object_id_queue *ids,
293 097b408a 2022-10-17 thomas struct got_object_idset *keep, struct got_object_idset *drop,
294 097b408a 2022-10-17 thomas struct got_object_idset *skip, struct got_repository *repo,
295 097b408a 2022-10-17 thomas got_pack_progress_cb progress_cb, void *progress_arg,
296 097b408a 2022-10-17 thomas struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg)
297 097b408a 2022-10-17 thomas {
298 097b408a 2022-10-17 thomas const struct got_error *err = NULL;
299 097b408a 2022-10-17 thomas struct got_object_id_queue next_ids;
300 097b408a 2022-10-17 thomas struct got_object_qid *qid, *tmp;
301 097b408a 2022-10-17 thomas struct recv_painted_commit_arg arg;
302 097b408a 2022-10-17 thomas
303 097b408a 2022-10-17 thomas STAILQ_INIT(&next_ids);
304 097b408a 2022-10-17 thomas
305 097b408a 2022-10-17 thomas err = got_privsep_send_painting_request(pack->privsep_child->ibuf,
306 097b408a 2022-10-17 thomas idx, id, color);
307 097b408a 2022-10-17 thomas if (err)
308 097b408a 2022-10-17 thomas return err;
309 097b408a 2022-10-17 thomas
310 097b408a 2022-10-17 thomas arg.ncolored = ncolored;
311 097b408a 2022-10-17 thomas arg.nqueued = nqueued;
312 097b408a 2022-10-17 thomas arg.nskip = nskip;
313 097b408a 2022-10-17 thomas arg.ids = ids;
314 097b408a 2022-10-17 thomas arg.keep = keep;
315 097b408a 2022-10-17 thomas arg.drop = drop;
316 097b408a 2022-10-17 thomas arg.skip = skip;
317 097b408a 2022-10-17 thomas arg.progress_cb = progress_cb;
318 097b408a 2022-10-17 thomas arg.progress_arg = progress_arg;
319 097b408a 2022-10-17 thomas arg.rl = rl;
320 097b408a 2022-10-17 thomas arg.cancel_cb = cancel_cb;
321 097b408a 2022-10-17 thomas arg.cancel_arg = cancel_arg;
322 097b408a 2022-10-17 thomas err = got_privsep_recv_painted_commits(&next_ids,
323 097b408a 2022-10-17 thomas recv_painted_commit, &arg, pack->privsep_child->ibuf);
324 097b408a 2022-10-17 thomas if (err)
325 097b408a 2022-10-17 thomas return err;
326 097b408a 2022-10-17 thomas
327 097b408a 2022-10-17 thomas STAILQ_FOREACH_SAFE(qid, &next_ids, entry, tmp) {
328 097b408a 2022-10-17 thomas struct got_object_qid *old_id;
329 097b408a 2022-10-17 thomas intptr_t qcolor, ocolor;
330 097b408a 2022-10-17 thomas STAILQ_FOREACH(old_id, ids, entry) {
331 097b408a 2022-10-17 thomas if (got_object_id_cmp(&qid->id, &old_id->id))
332 097b408a 2022-10-17 thomas continue;
333 097b408a 2022-10-17 thomas qcolor = (intptr_t)qid->data;
334 097b408a 2022-10-17 thomas ocolor = (intptr_t)old_id->data;
335 097b408a 2022-10-17 thomas STAILQ_REMOVE(&next_ids, qid, got_object_qid, entry);
336 097b408a 2022-10-17 thomas got_object_qid_free(qid);
337 097b408a 2022-10-17 thomas qid = NULL;
338 097b408a 2022-10-17 thomas if (qcolor != ocolor) {
339 097b408a 2022-10-17 thomas got_pack_paint_commit(old_id, qcolor);
340 097b408a 2022-10-17 thomas if (ocolor == COLOR_SKIP)
341 097b408a 2022-10-17 thomas (*nskip)--;
342 097b408a 2022-10-17 thomas else if (qcolor == COLOR_SKIP)
343 097b408a 2022-10-17 thomas (*nskip)++;
344 097b408a 2022-10-17 thomas }
345 097b408a 2022-10-17 thomas break;
346 097b408a 2022-10-17 thomas }
347 097b408a 2022-10-17 thomas }
348 097b408a 2022-10-17 thomas while (!STAILQ_EMPTY(&next_ids)) {
349 097b408a 2022-10-17 thomas qid = STAILQ_FIRST(&next_ids);
350 097b408a 2022-10-17 thomas STAILQ_REMOVE_HEAD(&next_ids, entry);
351 097b408a 2022-10-17 thomas got_pack_paint_commit(qid, color);
352 097b408a 2022-10-17 thomas STAILQ_INSERT_TAIL(ids, qid, entry);
353 097b408a 2022-10-17 thomas (*nqueued)++;
354 097b408a 2022-10-17 thomas if (color == COLOR_SKIP)
355 097b408a 2022-10-17 thomas (*nskip)++;
356 097b408a 2022-10-17 thomas }
357 097b408a 2022-10-17 thomas
358 097b408a 2022-10-17 thomas return err;
359 097b408a 2022-10-17 thomas }
360 097b408a 2022-10-17 thomas
361 097b408a 2022-10-17 thomas const struct got_error *
362 097b408a 2022-10-17 thomas got_pack_paint_commits(int *ncolored, struct got_object_id_queue *ids, int nids,
363 097b408a 2022-10-17 thomas struct got_object_idset *keep, struct got_object_idset *drop,
364 097b408a 2022-10-17 thomas struct got_object_idset *skip, struct got_repository *repo,
365 097b408a 2022-10-17 thomas got_pack_progress_cb progress_cb, void *progress_arg,
366 097b408a 2022-10-17 thomas struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg)
367 097b408a 2022-10-17 thomas {
368 097b408a 2022-10-17 thomas const struct got_error *err = NULL;
369 097b408a 2022-10-17 thomas struct got_commit_object *commit = NULL;
370 097b408a 2022-10-17 thomas struct got_packidx *packidx = NULL;
371 097b408a 2022-10-17 thomas struct got_pack *pack = NULL;
372 097b408a 2022-10-17 thomas const struct got_object_id_queue *parents;
373 097b408a 2022-10-17 thomas struct got_object_qid *qid = NULL;
374 097b408a 2022-10-17 thomas int nqueued = nids, nskip = 0;
375 097b408a 2022-10-17 thomas int idx;
376 097b408a 2022-10-17 thomas
377 097b408a 2022-10-17 thomas while (!STAILQ_EMPTY(ids) && nskip != nqueued) {
378 097b408a 2022-10-17 thomas intptr_t color;
379 097b408a 2022-10-17 thomas
380 097b408a 2022-10-17 thomas if (cancel_cb) {
381 097b408a 2022-10-17 thomas err = cancel_cb(cancel_arg);
382 097b408a 2022-10-17 thomas if (err)
383 097b408a 2022-10-17 thomas break;
384 097b408a 2022-10-17 thomas }
385 097b408a 2022-10-17 thomas
386 097b408a 2022-10-17 thomas qid = STAILQ_FIRST(ids);
387 097b408a 2022-10-17 thomas STAILQ_REMOVE_HEAD(ids, entry);
388 097b408a 2022-10-17 thomas nqueued--;
389 097b408a 2022-10-17 thomas color = (intptr_t)qid->data;
390 097b408a 2022-10-17 thomas if (color == COLOR_SKIP)
391 097b408a 2022-10-17 thomas nskip--;
392 097b408a 2022-10-17 thomas
393 097b408a 2022-10-17 thomas if (got_object_idset_contains(skip, &qid->id)) {
394 097b408a 2022-10-17 thomas got_object_qid_free(qid);
395 097b408a 2022-10-17 thomas qid = NULL;
396 097b408a 2022-10-17 thomas continue;
397 097b408a 2022-10-17 thomas }
398 097b408a 2022-10-17 thomas if (color == COLOR_KEEP &&
399 097b408a 2022-10-17 thomas got_object_idset_contains(keep, &qid->id)) {
400 097b408a 2022-10-17 thomas got_object_qid_free(qid);
401 097b408a 2022-10-17 thomas qid = NULL;
402 097b408a 2022-10-17 thomas continue;
403 097b408a 2022-10-17 thomas }
404 097b408a 2022-10-17 thomas if (color == COLOR_DROP &&
405 097b408a 2022-10-17 thomas got_object_idset_contains(drop, &qid->id)) {
406 097b408a 2022-10-17 thomas got_object_qid_free(qid);
407 097b408a 2022-10-17 thomas qid = NULL;
408 097b408a 2022-10-17 thomas continue;
409 097b408a 2022-10-17 thomas }
410 097b408a 2022-10-17 thomas
411 097b408a 2022-10-17 thomas /* Pinned pack may have moved to different cache slot. */
412 097b408a 2022-10-17 thomas pack = got_repo_get_pinned_pack(repo);
413 097b408a 2022-10-17 thomas
414 097b408a 2022-10-17 thomas if (packidx && pack) {
415 097b408a 2022-10-17 thomas idx = got_packidx_get_object_idx(packidx, &qid->id);
416 097b408a 2022-10-17 thomas if (idx != -1) {
417 097b408a 2022-10-17 thomas err = paint_packed_commits(pack, &qid->id,
418 097b408a 2022-10-17 thomas idx, color, ncolored, &nqueued, &nskip,
419 097b408a 2022-10-17 thomas ids, keep, drop, skip, repo,
420 097b408a 2022-10-17 thomas progress_cb, progress_arg, rl,
421 097b408a 2022-10-17 thomas cancel_cb, cancel_arg);
422 097b408a 2022-10-17 thomas if (err)
423 097b408a 2022-10-17 thomas break;
424 097b408a 2022-10-17 thomas got_object_qid_free(qid);
425 097b408a 2022-10-17 thomas qid = NULL;
426 097b408a 2022-10-17 thomas continue;
427 097b408a 2022-10-17 thomas }
428 097b408a 2022-10-17 thomas }
429 097b408a 2022-10-17 thomas
430 097b408a 2022-10-17 thomas switch (color) {
431 097b408a 2022-10-17 thomas case COLOR_KEEP:
432 097b408a 2022-10-17 thomas if (got_object_idset_contains(drop, &qid->id)) {
433 097b408a 2022-10-17 thomas err = got_pack_paint_commit(qid, COLOR_SKIP);
434 097b408a 2022-10-17 thomas if (err)
435 097b408a 2022-10-17 thomas goto done;
436 097b408a 2022-10-17 thomas } else
437 097b408a 2022-10-17 thomas (*ncolored)++;
438 097b408a 2022-10-17 thomas err = got_object_idset_add(keep, &qid->id, NULL);
439 097b408a 2022-10-17 thomas if (err)
440 097b408a 2022-10-17 thomas goto done;
441 097b408a 2022-10-17 thomas break;
442 097b408a 2022-10-17 thomas case COLOR_DROP:
443 097b408a 2022-10-17 thomas if (got_object_idset_contains(keep, &qid->id)) {
444 097b408a 2022-10-17 thomas err = got_pack_paint_commit(qid, COLOR_SKIP);
445 097b408a 2022-10-17 thomas if (err)
446 097b408a 2022-10-17 thomas goto done;
447 097b408a 2022-10-17 thomas } else
448 097b408a 2022-10-17 thomas (*ncolored)++;
449 097b408a 2022-10-17 thomas err = got_object_idset_add(drop, &qid->id, NULL);
450 097b408a 2022-10-17 thomas if (err)
451 097b408a 2022-10-17 thomas goto done;
452 097b408a 2022-10-17 thomas break;
453 097b408a 2022-10-17 thomas case COLOR_SKIP:
454 097b408a 2022-10-17 thomas if (!got_object_idset_contains(skip, &qid->id)) {
455 097b408a 2022-10-17 thomas err = got_object_idset_add(skip, &qid->id,
456 097b408a 2022-10-17 thomas NULL);
457 097b408a 2022-10-17 thomas if (err)
458 097b408a 2022-10-17 thomas goto done;
459 097b408a 2022-10-17 thomas }
460 097b408a 2022-10-17 thomas break;
461 097b408a 2022-10-17 thomas default:
462 097b408a 2022-10-17 thomas /* should not happen */
463 097b408a 2022-10-17 thomas err = got_error_fmt(GOT_ERR_NOT_IMPL,
464 097b408a 2022-10-17 thomas "%s invalid commit color %"PRIdPTR, __func__,
465 097b408a 2022-10-17 thomas color);
466 097b408a 2022-10-17 thomas goto done;
467 097b408a 2022-10-17 thomas }
468 097b408a 2022-10-17 thomas
469 097b408a 2022-10-17 thomas err = got_pack_report_progress(progress_cb, progress_arg, rl,
470 097b408a 2022-10-17 thomas *ncolored, 0, 0, 0L, 0, 0, 0, 0);
471 097b408a 2022-10-17 thomas if (err)
472 097b408a 2022-10-17 thomas break;
473 097b408a 2022-10-17 thomas
474 097b408a 2022-10-17 thomas err = got_object_open_as_commit(&commit, repo, &qid->id);
475 097b408a 2022-10-17 thomas if (err)
476 097b408a 2022-10-17 thomas break;
477 097b408a 2022-10-17 thomas
478 097b408a 2022-10-17 thomas parents = got_object_commit_get_parent_ids(commit);
479 097b408a 2022-10-17 thomas if (parents) {
480 097b408a 2022-10-17 thomas struct got_object_qid *pid;
481 097b408a 2022-10-17 thomas color = (intptr_t)qid->data;
482 097b408a 2022-10-17 thomas STAILQ_FOREACH(pid, parents, entry) {
483 097b408a 2022-10-17 thomas err = got_pack_queue_commit_id(ids, &pid->id,
484 097b408a 2022-10-17 thomas color, repo);
485 097b408a 2022-10-17 thomas if (err)
486 097b408a 2022-10-17 thomas break;
487 097b408a 2022-10-17 thomas nqueued++;
488 097b408a 2022-10-17 thomas if (color == COLOR_SKIP)
489 097b408a 2022-10-17 thomas nskip++;
490 097b408a 2022-10-17 thomas }
491 097b408a 2022-10-17 thomas }
492 097b408a 2022-10-17 thomas
493 097b408a 2022-10-17 thomas if (pack == NULL && (commit->flags & GOT_COMMIT_FLAG_PACKED)) {
494 097b408a 2022-10-17 thomas if (packidx == NULL) {
495 097b408a 2022-10-17 thomas err = got_pack_find_pack_for_commit_painting(
496 097b408a 2022-10-17 thomas &packidx, ids, nqueued, repo);
497 097b408a 2022-10-17 thomas if (err)
498 097b408a 2022-10-17 thomas goto done;
499 097b408a 2022-10-17 thomas }
500 097b408a 2022-10-17 thomas if (packidx != NULL) {
501 097b408a 2022-10-17 thomas err = got_pack_cache_pack_for_packidx(&pack,
502 097b408a 2022-10-17 thomas packidx, repo);
503 097b408a 2022-10-17 thomas if (err)
504 097b408a 2022-10-17 thomas goto done;
505 097b408a 2022-10-17 thomas if (pack->privsep_child == NULL) {
506 097b408a 2022-10-17 thomas err = got_pack_start_privsep_child(
507 097b408a 2022-10-17 thomas pack, packidx);
508 097b408a 2022-10-17 thomas if (err)
509 097b408a 2022-10-17 thomas goto done;
510 097b408a 2022-10-17 thomas }
511 097b408a 2022-10-17 thomas err = got_privsep_init_commit_painting(
512 097b408a 2022-10-17 thomas pack->privsep_child->ibuf);
513 097b408a 2022-10-17 thomas if (err)
514 097b408a 2022-10-17 thomas goto done;
515 097b408a 2022-10-17 thomas err = send_idset(pack->privsep_child->ibuf,
516 097b408a 2022-10-17 thomas keep);
517 097b408a 2022-10-17 thomas if (err)
518 097b408a 2022-10-17 thomas goto done;
519 097b408a 2022-10-17 thomas err = send_idset(pack->privsep_child->ibuf, drop);
520 097b408a 2022-10-17 thomas if (err)
521 097b408a 2022-10-17 thomas goto done;
522 097b408a 2022-10-17 thomas err = send_idset(pack->privsep_child->ibuf, skip);
523 097b408a 2022-10-17 thomas if (err)
524 097b408a 2022-10-17 thomas goto done;
525 097b408a 2022-10-17 thomas err = got_repo_pin_pack(repo, packidx, pack);
526 097b408a 2022-10-17 thomas if (err)
527 097b408a 2022-10-17 thomas goto done;
528 097b408a 2022-10-17 thomas }
529 097b408a 2022-10-17 thomas }
530 097b408a 2022-10-17 thomas
531 097b408a 2022-10-17 thomas got_object_commit_close(commit);
532 097b408a 2022-10-17 thomas commit = NULL;
533 097b408a 2022-10-17 thomas
534 097b408a 2022-10-17 thomas got_object_qid_free(qid);
535 097b408a 2022-10-17 thomas qid = NULL;
536 097b408a 2022-10-17 thomas }
537 097b408a 2022-10-17 thomas done:
538 097b408a 2022-10-17 thomas if (pack) {
539 097b408a 2022-10-17 thomas const struct got_error *pack_err;
540 097b408a 2022-10-17 thomas pack_err = got_privsep_send_painting_commits_done(
541 097b408a 2022-10-17 thomas pack->privsep_child->ibuf);
542 097b408a 2022-10-17 thomas if (err == NULL)
543 097b408a 2022-10-17 thomas err = pack_err;
544 097b408a 2022-10-17 thomas }
545 097b408a 2022-10-17 thomas if (commit)
546 097b408a 2022-10-17 thomas got_object_commit_close(commit);
547 097b408a 2022-10-17 thomas got_object_qid_free(qid);
548 097b408a 2022-10-17 thomas got_repo_unpin_pack(repo);
549 097b408a 2022-10-17 thomas return err;
550 097b408a 2022-10-17 thomas }
551 097b408a 2022-10-17 thomas
552 097b408a 2022-10-17 thomas struct load_packed_obj_arg {
553 097b408a 2022-10-17 thomas /* output parameters: */
554 097b408a 2022-10-17 thomas struct got_object_id *id;
555 097b408a 2022-10-17 thomas char *dpath;
556 097b408a 2022-10-17 thomas time_t mtime;
557 097b408a 2022-10-17 thomas
558 097b408a 2022-10-17 thomas /* input parameters: */
559 097b408a 2022-10-17 thomas uint32_t seed;
560 097b408a 2022-10-17 thomas int want_meta;
561 097b408a 2022-10-17 thomas struct got_object_idset *idset;
562 097b408a 2022-10-17 thomas struct got_object_idset *idset_exclude;
563 097b408a 2022-10-17 thomas int loose_obj_only;
564 097b408a 2022-10-17 thomas int *ncolored;
565 097b408a 2022-10-17 thomas int *nfound;
566 097b408a 2022-10-17 thomas int *ntrees;
567 097b408a 2022-10-17 thomas got_pack_progress_cb progress_cb;
568 097b408a 2022-10-17 thomas void *progress_arg;
569 097b408a 2022-10-17 thomas struct got_ratelimit *rl;
570 097b408a 2022-10-17 thomas got_cancel_cb cancel_cb;
571 097b408a 2022-10-17 thomas void *cancel_arg;
572 097b408a 2022-10-17 thomas };
573 097b408a 2022-10-17 thomas
574 097b408a 2022-10-17 thomas static const struct got_error *
575 097b408a 2022-10-17 thomas load_packed_commit_id(void *arg, time_t mtime, struct got_object_id *id,
576 097b408a 2022-10-17 thomas struct got_repository *repo)
577 097b408a 2022-10-17 thomas {
578 097b408a 2022-10-17 thomas struct load_packed_obj_arg *a = arg;
579 097b408a 2022-10-17 thomas
580 097b408a 2022-10-17 thomas if (got_object_idset_contains(a->idset, id) ||
581 097b408a 2022-10-17 thomas got_object_idset_contains(a->idset_exclude, id))
582 097b408a 2022-10-17 thomas return NULL;
583 097b408a 2022-10-17 thomas
584 097b408a 2022-10-17 thomas return got_pack_add_object(a->want_meta,
585 097b408a 2022-10-17 thomas a->want_meta ? a->idset : a->idset_exclude,
586 097b408a 2022-10-17 thomas id, "", GOT_OBJ_TYPE_COMMIT, mtime, a->seed, a->loose_obj_only,
587 097b408a 2022-10-17 thomas repo, a->ncolored, a->nfound, a->ntrees,
588 097b408a 2022-10-17 thomas a->progress_cb, a->progress_arg, a->rl);
589 097b408a 2022-10-17 thomas }
590 097b408a 2022-10-17 thomas
591 097b408a 2022-10-17 thomas static const struct got_error *
592 097b408a 2022-10-17 thomas load_packed_tree_ids(void *arg, struct got_tree_object *tree, time_t mtime,
593 097b408a 2022-10-17 thomas struct got_object_id *id, const char *dpath, struct got_repository *repo)
594 097b408a 2022-10-17 thomas {
595 097b408a 2022-10-17 thomas const struct got_error *err;
596 097b408a 2022-10-17 thomas struct load_packed_obj_arg *a = arg;
597 097b408a 2022-10-17 thomas const char *relpath;
598 097b408a 2022-10-17 thomas
599 097b408a 2022-10-17 thomas /*
600 097b408a 2022-10-17 thomas * When we receive a tree's ID and path but not the tree itself,
601 097b408a 2022-10-17 thomas * this tree object was not found in the pack file. This is the
602 097b408a 2022-10-17 thomas * last time we are being called for this optimized traversal.
603 097b408a 2022-10-17 thomas * Return from here and switch to loading objects the slow way.
604 097b408a 2022-10-17 thomas */
605 097b408a 2022-10-17 thomas if (tree == NULL) {
606 097b408a 2022-10-17 thomas free(a->id);
607 097b408a 2022-10-17 thomas a->id = got_object_id_dup(id);
608 097b408a 2022-10-17 thomas if (a->id == NULL) {
609 097b408a 2022-10-17 thomas err = got_error_from_errno("got_object_id_dup");
610 097b408a 2022-10-17 thomas free(a->dpath);
611 097b408a 2022-10-17 thomas a->dpath = NULL;
612 097b408a 2022-10-17 thomas return err;
613 097b408a 2022-10-17 thomas }
614 097b408a 2022-10-17 thomas
615 097b408a 2022-10-17 thomas free(a->dpath);
616 097b408a 2022-10-17 thomas a->dpath = strdup(dpath);
617 097b408a 2022-10-17 thomas if (a->dpath == NULL) {
618 097b408a 2022-10-17 thomas err = got_error_from_errno("strdup");
619 097b408a 2022-10-17 thomas free(a->id);
620 097b408a 2022-10-17 thomas a->id = NULL;
621 097b408a 2022-10-17 thomas return err;
622 097b408a 2022-10-17 thomas }
623 097b408a 2022-10-17 thomas
624 097b408a 2022-10-17 thomas a->mtime = mtime;
625 097b408a 2022-10-17 thomas return NULL;
626 097b408a 2022-10-17 thomas }
627 097b408a 2022-10-17 thomas
628 097b408a 2022-10-17 thomas if (got_object_idset_contains(a->idset, id) ||
629 097b408a 2022-10-17 thomas got_object_idset_contains(a->idset_exclude, id))
630 097b408a 2022-10-17 thomas return NULL;
631 097b408a 2022-10-17 thomas
632 097b408a 2022-10-17 thomas relpath = dpath;
633 097b408a 2022-10-17 thomas while (relpath[0] == '/')
634 097b408a 2022-10-17 thomas relpath++;
635 097b408a 2022-10-17 thomas
636 097b408a 2022-10-17 thomas err = got_pack_add_object(a->want_meta,
637 097b408a 2022-10-17 thomas a->want_meta ? a->idset : a->idset_exclude,
638 097b408a 2022-10-17 thomas id, relpath, GOT_OBJ_TYPE_TREE, mtime, a->seed,
639 097b408a 2022-10-17 thomas a->loose_obj_only, repo, a->ncolored, a->nfound, a->ntrees,
640 097b408a 2022-10-17 thomas a->progress_cb, a->progress_arg, a->rl);
641 097b408a 2022-10-17 thomas if (err)
642 097b408a 2022-10-17 thomas return err;
643 097b408a 2022-10-17 thomas
644 097b408a 2022-10-17 thomas return got_pack_load_tree_entries(NULL, a->want_meta, a->idset,
645 097b408a 2022-10-17 thomas a->idset_exclude, tree, dpath, mtime, a->seed, repo,
646 097b408a 2022-10-17 thomas a->loose_obj_only, a->ncolored, a->nfound, a->ntrees,
647 097b408a 2022-10-17 thomas a->progress_cb, a->progress_arg, a->rl,
648 097b408a 2022-10-17 thomas a->cancel_cb, a->cancel_arg);
649 097b408a 2022-10-17 thomas }
650 097b408a 2022-10-17 thomas
651 097b408a 2022-10-17 thomas const struct got_error *
652 097b408a 2022-10-17 thomas got_pack_load_packed_object_ids(int *found_all_objects,
653 097b408a 2022-10-17 thomas struct got_object_id **ours, int nours,
654 097b408a 2022-10-17 thomas struct got_object_id **theirs, int ntheirs,
655 097b408a 2022-10-17 thomas int want_meta, uint32_t seed, struct got_object_idset *idset,
656 097b408a 2022-10-17 thomas struct got_object_idset *idset_exclude, int loose_obj_only,
657 097b408a 2022-10-17 thomas struct got_repository *repo, struct got_packidx *packidx,
658 097b408a 2022-10-17 thomas int *ncolored, int *nfound, int *ntrees,
659 097b408a 2022-10-17 thomas got_pack_progress_cb progress_cb, void *progress_arg,
660 097b408a 2022-10-17 thomas struct got_ratelimit *rl, got_cancel_cb cancel_cb, void *cancel_arg)
661 097b408a 2022-10-17 thomas {
662 097b408a 2022-10-17 thomas const struct got_error *err = NULL;
663 097b408a 2022-10-17 thomas struct load_packed_obj_arg lpa;
664 097b408a 2022-10-17 thomas
665 097b408a 2022-10-17 thomas memset(&lpa, 0, sizeof(lpa));
666 097b408a 2022-10-17 thomas lpa.seed = seed;
667 097b408a 2022-10-17 thomas lpa.want_meta = want_meta;
668 097b408a 2022-10-17 thomas lpa.idset = idset;
669 097b408a 2022-10-17 thomas lpa.idset_exclude = idset_exclude;
670 097b408a 2022-10-17 thomas lpa.loose_obj_only = loose_obj_only;
671 097b408a 2022-10-17 thomas lpa.ncolored = ncolored;
672 097b408a 2022-10-17 thomas lpa.nfound = nfound;
673 097b408a 2022-10-17 thomas lpa.ntrees = ntrees;
674 097b408a 2022-10-17 thomas lpa.progress_cb = progress_cb;
675 097b408a 2022-10-17 thomas lpa.progress_arg = progress_arg;
676 097b408a 2022-10-17 thomas lpa.rl = rl;
677 097b408a 2022-10-17 thomas lpa.cancel_cb = cancel_cb;
678 097b408a 2022-10-17 thomas lpa.cancel_arg = cancel_arg;
679 097b408a 2022-10-17 thomas
680 097b408a 2022-10-17 thomas /* Attempt to load objects via got-read-pack, as far as possible. */
681 097b408a 2022-10-17 thomas err = got_object_enumerate(found_all_objects, load_packed_commit_id,
682 097b408a 2022-10-17 thomas load_packed_tree_ids, &lpa, ours, nours, theirs, ntheirs,
683 097b408a 2022-10-17 thomas packidx, repo);
684 097b408a 2022-10-17 thomas if (err)
685 097b408a 2022-10-17 thomas return err;
686 097b408a 2022-10-17 thomas
687 097b408a 2022-10-17 thomas if (lpa.id == NULL)
688 097b408a 2022-10-17 thomas return NULL;
689 097b408a 2022-10-17 thomas
690 097b408a 2022-10-17 thomas /*
691 097b408a 2022-10-17 thomas * An incomplete tree hierarchy was present in the pack file
692 097b408a 2022-10-17 thomas * and caused loading to be aborted.
693 097b408a 2022-10-17 thomas * Continue loading trees the slow way.
694 097b408a 2022-10-17 thomas */
695 097b408a 2022-10-17 thomas err = got_pack_load_tree(want_meta, idset, idset_exclude,
696 097b408a 2022-10-17 thomas lpa.id, lpa.dpath, lpa.mtime, seed, repo, loose_obj_only,
697 097b408a 2022-10-17 thomas ncolored, nfound, ntrees, progress_cb, progress_arg, rl,
698 097b408a 2022-10-17 thomas cancel_cb, cancel_arg);
699 097b408a 2022-10-17 thomas free(lpa.id);
700 097b408a 2022-10-17 thomas free(lpa.dpath);
701 097b408a 2022-10-17 thomas return err;
702 097b408a 2022-10-17 thomas }