2 * Copyright (c) 2022 Stefan Sperling <stsp@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include "got_compat.h"
19 #include <sys/queue.h>
21 #include <sys/types.h>
38 #include "got_error.h"
39 #include "got_repository.h"
40 #include "got_object.h"
41 #include "got_reference.h"
44 #include "got_cancel.h"
45 #include "got_commit_graph.h"
46 #include "got_opentemp.h"
48 #include "got_lib_delta.h"
49 #include "got_lib_delta_cache.h"
50 #include "got_lib_hash.h"
51 #include "got_lib_object.h"
52 #include "got_lib_object_cache.h"
53 #include "got_lib_object_idset.h"
54 #include "got_lib_object_parse.h"
55 #include "got_lib_ratelimit.h"
56 #include "got_lib_pack.h"
57 #include "got_lib_pack_index.h"
58 #include "got_lib_repository.h"
59 #include "got_lib_poll.h"
63 #include "repo_write.h"
66 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
69 static struct repo_write
{
72 struct got_repository
*repo
;
76 struct gotd_imsgev session_iev
;
77 struct got_pathlist_head
*protected_tag_namespaces
;
78 struct got_pathlist_head
*protected_branch_namespaces
;
79 struct got_pathlist_head
*protected_branches
;
89 struct gotd_ref_update
{
90 STAILQ_ENTRY(gotd_ref_update
) entry
;
91 struct got_reference
*ref
;
94 struct got_object_id old_id
;
95 struct got_object_id new_id
;
97 STAILQ_HEAD(gotd_ref_updates
, gotd_ref_update
);
99 static struct repo_write_client
{
103 struct got_pack pack
;
104 uint8_t pack_sha1
[SHA1_DIGEST_LENGTH
];
106 struct gotd_ref_updates ref_updates
;
113 static volatile sig_atomic_t sigint_received
;
114 static volatile sig_atomic_t sigterm_received
;
117 catch_sigint(int signo
)
123 catch_sigterm(int signo
)
125 sigterm_received
= 1;
128 static const struct got_error
*
129 check_cancelled(void *arg
)
131 if (sigint_received
|| sigterm_received
)
132 return got_error(GOT_ERR_CANCELLED
);
137 static const struct got_error
*
138 send_peeled_tag_ref(struct got_reference
*ref
, struct got_object
*obj
,
139 struct imsgbuf
*ibuf
)
141 const struct got_error
*err
= NULL
;
142 struct got_tag_object
*tag
;
144 char *peeled_refname
= NULL
;
145 struct got_object_id
*id
;
148 err
= got_object_tag_open(&tag
, repo_write
.repo
, obj
);
152 if (asprintf(&peeled_refname
, "%s^{}", got_ref_get_name(ref
)) == -1) {
153 err
= got_error_from_errno("asprintf");
157 id
= got_object_tag_get_object_id(tag
);
158 namelen
= strlen(peeled_refname
);
160 len
= sizeof(struct gotd_imsg_ref
) + namelen
;
161 if (len
> MAX_IMSGSIZE
- IMSG_HEADER_SIZE
) {
162 err
= got_error(GOT_ERR_NO_SPACE
);
166 wbuf
= imsg_create(ibuf
, GOTD_IMSG_REF
, PROC_REPO_WRITE
,
167 repo_write
.pid
, len
);
169 err
= got_error_from_errno("imsg_create REF");
173 /* Keep in sync with struct gotd_imsg_ref definition. */
174 if (imsg_add(wbuf
, id
->hash
, SHA1_DIGEST_LENGTH
) == -1) {
175 err
= got_error_from_errno("imsg_add REF");
178 if (imsg_add(wbuf
, &namelen
, sizeof(namelen
)) == -1) {
179 err
= got_error_from_errno("imsg_add REF");
182 if (imsg_add(wbuf
, peeled_refname
, namelen
) == -1) {
183 err
= got_error_from_errno("imsg_add REF");
187 imsg_close(ibuf
, wbuf
);
189 got_object_tag_close(tag
);
193 static const struct got_error
*
194 send_ref(struct got_reference
*ref
, struct imsgbuf
*ibuf
)
196 const struct got_error
*err
;
197 const char *refname
= got_ref_get_name(ref
);
199 struct got_object_id
*id
= NULL
;
200 struct got_object
*obj
= NULL
;
204 namelen
= strlen(refname
);
206 len
= sizeof(struct gotd_imsg_ref
) + namelen
;
207 if (len
> MAX_IMSGSIZE
- IMSG_HEADER_SIZE
)
208 return got_error(GOT_ERR_NO_SPACE
);
210 err
= got_ref_resolve(&id
, repo_write
.repo
, ref
);
214 wbuf
= imsg_create(ibuf
, GOTD_IMSG_REF
, PROC_REPO_WRITE
,
215 repo_write
.pid
, len
);
217 err
= got_error_from_errno("imsg_create REF");
221 /* Keep in sync with struct gotd_imsg_ref definition. */
222 if (imsg_add(wbuf
, id
->hash
, SHA1_DIGEST_LENGTH
) == -1)
223 return got_error_from_errno("imsg_add REF");
224 if (imsg_add(wbuf
, &namelen
, sizeof(namelen
)) == -1)
225 return got_error_from_errno("imsg_add REF");
226 if (imsg_add(wbuf
, refname
, namelen
) == -1)
227 return got_error_from_errno("imsg_add REF");
229 imsg_close(ibuf
, wbuf
);
231 err
= got_object_open(&obj
, repo_write
.repo
, id
);
234 if (obj
->type
== GOT_OBJ_TYPE_TAG
)
235 err
= send_peeled_tag_ref(ref
, obj
, ibuf
);
238 got_object_close(obj
);
243 static const struct got_error
*
244 list_refs(struct imsg
*imsg
)
246 const struct got_error
*err
;
247 struct repo_write_client
*client
= &repo_write_client
;
248 struct got_reflist_head refs
;
249 struct got_reflist_entry
*re
;
251 struct gotd_imsg_reflist irefs
;
256 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
258 return got_error(GOT_ERR_PRIVSEP_LEN
);
260 if (repo_write
.refs_listed
) {
261 return got_error_msg(GOT_ERR_CLIENT_ID
,
262 "duplicate list-refs request");
264 repo_write
.refs_listed
= 1;
266 client
->fd
= imsg_get_fd(imsg
);
267 if (client
->fd
== -1)
268 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
270 client
->nref_updates
= 0;
271 client
->nref_del
= 0;
272 client
->nref_new
= 0;
273 client
->nref_move
= 0;
275 if (imsgbuf_init(&ibuf
, client
->fd
) == -1)
276 return got_error_from_errno("imsgbuf_init");
277 imsgbuf_allow_fdpass(&ibuf
);
279 err
= got_ref_list(&refs
, repo_write
.repo
, "",
280 got_ref_cmp_by_name
, NULL
);
284 memset(&irefs
, 0, sizeof(irefs
));
285 TAILQ_FOREACH(re
, &refs
, entry
) {
286 struct got_object_id
*id
;
289 if (got_ref_is_symbolic(re
->ref
))
294 /* Account for a peeled tag refs. */
295 err
= got_ref_resolve(&id
, repo_write
.repo
, re
->ref
);
298 err
= got_object_get_type(&obj_type
, repo_write
.repo
, id
);
302 if (obj_type
== GOT_OBJ_TYPE_TAG
)
306 if (imsg_compose(&ibuf
, GOTD_IMSG_REFLIST
, PROC_REPO_WRITE
,
307 repo_write
.pid
, -1, &irefs
, sizeof(irefs
)) == -1) {
308 err
= got_error_from_errno("imsg_compose REFLIST");
312 TAILQ_FOREACH(re
, &refs
, entry
) {
313 if (got_ref_is_symbolic(re
->ref
))
315 err
= send_ref(re
->ref
, &ibuf
);
320 err
= gotd_imsg_flush(&ibuf
);
322 got_ref_list_free(&refs
);
323 imsgbuf_clear(&ibuf
);
327 static const struct got_error
*
328 validate_namespace(const char *namespace)
330 size_t len
= strlen(namespace);
332 if (len
< 5 || strncmp("refs/", namespace, 5) != 0 ||
333 namespace[len
-1] != '/') {
334 return got_error_fmt(GOT_ERR_BAD_REF_NAME
,
335 "reference namespace '%s'", namespace);
341 static const struct got_error
*
342 protect_ref_namespace(const char *refname
, const char *namespace)
344 const struct got_error
*err
;
346 err
= validate_namespace(namespace);
350 if (strncmp(namespace, refname
, strlen(namespace)) == 0)
351 return got_error_fmt(GOT_ERR_REFS_PROTECTED
, "%s", namespace);
356 static const struct got_error
*
357 verify_object_type(struct got_object_id
*id
, int expected_obj_type
,
358 struct got_pack
*pack
, struct got_packidx
*packidx
)
360 const struct got_error
*err
;
361 char hex
[SHA1_DIGEST_STRING_LENGTH
];
362 struct got_object
*obj
;
366 idx
= got_packidx_get_object_idx(packidx
, id
);
368 got_object_id_hex(id
, hex
, sizeof(hex
));
369 return got_error_fmt(GOT_ERR_BAD_PACKFILE
,
370 "object %s is missing from pack file", hex
);
373 err
= got_object_open_from_packfile(&obj
, id
, pack
, packidx
,
374 idx
, repo_write
.repo
);
378 if (obj
->type
!= expected_obj_type
) {
379 got_object_id_hex(id
, hex
, sizeof(hex
));
380 got_object_type_label(&typestr
, expected_obj_type
);
381 err
= got_error_fmt(GOT_ERR_OBJ_TYPE
,
382 "%s is not pointing at a %s object", hex
, typestr
);
384 got_object_close(obj
);
388 static const struct got_error
*
389 protect_tag_namespace(const char *namespace, struct got_pack
*pack
,
390 struct got_packidx
*packidx
, struct gotd_ref_update
*ref_update
)
392 const struct got_error
*err
;
394 err
= validate_namespace(namespace);
398 if (strncmp(namespace, got_ref_get_name(ref_update
->ref
),
399 strlen(namespace)) != 0)
402 if (!ref_update
->ref_is_new
)
403 return got_error_fmt(GOT_ERR_REFS_PROTECTED
, "%s", namespace);
405 return verify_object_type(&ref_update
->new_id
, GOT_OBJ_TYPE_TAG
,
409 static const struct got_error
*
410 protect_require_yca(struct got_object_id
*tip_id
,
411 size_t max_commits_to_traverse
, struct got_pack
*pack
,
412 struct got_packidx
*packidx
, struct got_reference
*ref
)
414 const struct got_error
*err
;
417 struct got_object_id
*expected_yca_id
= NULL
;
418 struct got_object
*obj
= NULL
;
419 struct got_commit_object
*commit
= NULL
;
420 char hex
[SHA1_DIGEST_STRING_LENGTH
];
421 const struct got_object_id_queue
*parent_ids
;
422 struct got_object_id_queue ids
;
423 struct got_object_qid
*pid
, *qid
;
424 struct got_object_idset
*traversed_set
= NULL
;
425 int found_yca
= 0, obj_type
;
429 err
= got_ref_resolve(&expected_yca_id
, repo_write
.repo
, ref
);
433 err
= got_object_get_type(&obj_type
, repo_write
.repo
, expected_yca_id
);
437 if (obj_type
!= GOT_OBJ_TYPE_COMMIT
) {
438 got_object_id_hex(expected_yca_id
, hex
, sizeof(hex
));
439 err
= got_error_fmt(GOT_ERR_OBJ_TYPE
,
440 "%s is not pointing at a commit object", hex
);
444 traversed_set
= got_object_idset_alloc();
445 if (traversed_set
== NULL
) {
446 err
= got_error_from_errno("got_object_idset_alloc");
450 err
= got_object_qid_alloc(&qid
, tip_id
);
453 STAILQ_INSERT_TAIL(&ids
, qid
, entry
);
454 while (!STAILQ_EMPTY(&ids
)) {
455 err
= check_cancelled(NULL
);
459 qid
= STAILQ_FIRST(&ids
);
460 if (got_object_id_cmp(&qid
->id
, expected_yca_id
) == 0) {
465 if (got_object_idset_num_elements(traversed_set
) >=
466 max_commits_to_traverse
)
469 if (got_object_idset_contains(traversed_set
, &qid
->id
)) {
470 STAILQ_REMOVE_HEAD(&ids
, entry
);
471 got_object_qid_free(qid
);
475 err
= got_object_idset_add(traversed_set
, &qid
->id
, NULL
);
479 err
= got_object_open(&obj
, repo_write
.repo
, &qid
->id
);
480 if (err
&& err
->code
!= GOT_ERR_NO_OBJ
)
484 err
= got_object_commit_open(&commit
, repo_write
.repo
,
491 idx
= got_packidx_get_object_idx(packidx
, &qid
->id
);
493 got_object_id_hex(&qid
->id
, hex
, sizeof(hex
));
494 err
= got_error_fmt(GOT_ERR_BAD_PACKFILE
,
495 "object %s is missing from pack file", hex
);
499 err
= got_object_open_from_packfile(&obj
, &qid
->id
,
500 pack
, packidx
, idx
, repo_write
.repo
);
504 if (obj
->type
!= GOT_OBJ_TYPE_COMMIT
) {
505 got_object_id_hex(&qid
->id
, hex
, sizeof(hex
));
506 err
= got_error_fmt(GOT_ERR_OBJ_TYPE
,
507 "%s is not pointing at a commit object",
512 err
= got_packfile_extract_object_to_mem(&buf
, &len
,
517 err
= got_object_parse_commit(&commit
, buf
, len
,
526 got_object_close(obj
);
529 STAILQ_REMOVE_HEAD(&ids
, entry
);
530 got_object_qid_free(qid
);
533 if (got_object_commit_get_nparents(commit
) == 0)
536 parent_ids
= got_object_commit_get_parent_ids(commit
);
537 STAILQ_FOREACH(pid
, parent_ids
, entry
) {
538 err
= check_cancelled(NULL
);
541 err
= got_object_qid_alloc(&qid
, &pid
->id
);
544 STAILQ_INSERT_TAIL(&ids
, qid
, entry
);
547 got_object_commit_close(commit
);
552 err
= got_error_fmt(GOT_ERR_REF_PROTECTED
, "%s",
553 got_ref_get_name(ref
));
556 got_object_idset_free(traversed_set
);
557 got_object_id_queue_free(&ids
);
560 got_object_close(obj
);
562 got_object_commit_close(commit
);
563 free(expected_yca_id
);
567 static const struct got_error
*
568 protect_branch_namespace(const char *namespace, struct got_pack
*pack
,
569 struct got_packidx
*packidx
, struct gotd_ref_update
*ref_update
)
571 const struct got_error
*err
;
573 err
= validate_namespace(namespace);
577 if (strncmp(namespace, got_ref_get_name(ref_update
->ref
),
578 strlen(namespace)) != 0)
581 if (ref_update
->ref_is_new
) {
582 return verify_object_type(&ref_update
->new_id
,
583 GOT_OBJ_TYPE_COMMIT
, pack
, packidx
);
586 return protect_require_yca(&ref_update
->new_id
,
587 be32toh(packidx
->hdr
.fanout_table
[0xff]), pack
, packidx
,
591 static const struct got_error
*
592 protect_branch(const char *refname
, struct got_pack
*pack
,
593 struct got_packidx
*packidx
, struct gotd_ref_update
*ref_update
)
595 if (strcmp(refname
, got_ref_get_name(ref_update
->ref
)) != 0)
598 /* Always allow new branches to be created. */
599 if (ref_update
->ref_is_new
) {
600 return verify_object_type(&ref_update
->new_id
,
601 GOT_OBJ_TYPE_COMMIT
, pack
, packidx
);
604 return protect_require_yca(&ref_update
->new_id
,
605 be32toh(packidx
->hdr
.fanout_table
[0xff]), pack
, packidx
,
609 static const struct got_error
*
610 recv_ref_update(struct imsg
*imsg
)
612 static const char zero_id
[SHA1_DIGEST_LENGTH
];
613 const struct got_error
*err
= NULL
;
614 struct repo_write_client
*client
= &repo_write_client
;
615 struct gotd_imsg_ref_update iref
;
617 char *refname
= NULL
;
618 struct got_reference
*ref
= NULL
;
619 struct got_object_id
*id
= NULL
;
621 struct gotd_ref_update
*ref_update
= NULL
;
623 log_debug("ref-update received");
625 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
626 if (datalen
< sizeof(iref
))
627 return got_error(GOT_ERR_PRIVSEP_LEN
);
628 memcpy(&iref
, imsg
->data
, sizeof(iref
));
629 if (datalen
!= sizeof(iref
) + iref
.name_len
)
630 return got_error(GOT_ERR_PRIVSEP_LEN
);
632 if (imsgbuf_init(&ibuf
, client
->fd
))
633 return got_error_from_errno("imsgbuf_init");
634 imsgbuf_allow_fdpass(&ibuf
);
636 refname
= strndup(imsg
->data
+ sizeof(iref
), iref
.name_len
);
637 if (refname
== NULL
) {
638 err
= got_error_from_errno("strndup");
642 ref_update
= calloc(1, sizeof(*ref_update
));
643 if (ref_update
== NULL
) {
644 err
= got_error_from_errno("malloc");
648 memcpy(ref_update
->old_id
.hash
, iref
.old_id
, SHA1_DIGEST_LENGTH
);
649 memcpy(ref_update
->new_id
.hash
, iref
.new_id
, SHA1_DIGEST_LENGTH
);
651 err
= got_ref_open(&ref
, repo_write
.repo
, refname
, 0);
653 if (err
->code
!= GOT_ERR_NOT_REF
)
655 if (memcmp(ref_update
->new_id
.hash
,
656 zero_id
, sizeof(zero_id
)) == 0) {
657 err
= got_error_fmt(GOT_ERR_BAD_OBJ_ID
,
661 err
= got_ref_alloc(&ref
, refname
, &ref_update
->new_id
);
664 ref_update
->ref_is_new
= 1;
667 if (got_ref_is_symbolic(ref
)) {
668 err
= got_error_fmt(GOT_ERR_BAD_REF_TYPE
,
669 "'%s' is a symbolic reference and cannot "
670 "be updated", got_ref_get_name(ref
));
673 if (strncmp("refs/", got_ref_get_name(ref
), 5) != 0) {
674 err
= got_error_fmt(GOT_ERR_BAD_REF_NAME
,
675 "%s: does not begin with 'refs/'",
676 got_ref_get_name(ref
));
680 err
= protect_ref_namespace(got_ref_get_name(ref
), "refs/got/");
683 err
= protect_ref_namespace(got_ref_get_name(ref
), "refs/remotes/");
687 if (!ref_update
->ref_is_new
) {
689 * Ensure the client's idea of this update is still valid.
690 * At this point we can only return an error, to prevent
691 * the client from uploading a pack file which will likely
692 * have to be discarded.
694 err
= got_ref_resolve(&id
, repo_write
.repo
, ref
);
698 if (got_object_id_cmp(id
, &ref_update
->old_id
) != 0) {
699 err
= got_error_fmt(GOT_ERR_REF_BUSY
,
700 "%s has been modified by someone else "
701 "while transaction was in progress",
702 got_ref_get_name(ref
));
707 gotd_imsg_send_ack(&ref_update
->new_id
, &ibuf
, PROC_REPO_WRITE
,
710 ref_update
->ref
= ref
;
711 if (memcmp(ref_update
->new_id
.hash
, zero_id
, sizeof(zero_id
)) == 0) {
712 ref_update
->delete_ref
= 1;
715 STAILQ_INSERT_HEAD(&client
->ref_updates
, ref_update
, entry
);
716 client
->nref_updates
++;
728 static const struct got_error
*
729 pack_index_progress(void *arg
, uint32_t nobj_total
, uint32_t nobj_indexed
,
730 uint32_t nobj_loose
, uint32_t nobj_resolved
)
732 int p_indexed
= 0, p_resolved
= 0;
733 int nobj_delta
= nobj_total
- nobj_loose
;
736 p_indexed
= (nobj_indexed
* 100) / nobj_total
;
739 p_resolved
= (nobj_resolved
* 100) / nobj_delta
;
741 if (p_resolved
> 0) {
742 log_debug("indexing %d objects %d%%; resolving %d deltas %d%%",
743 nobj_total
, p_indexed
, nobj_delta
, p_resolved
);
745 log_debug("indexing %d objects %d%%", nobj_total
, p_indexed
);
750 static const struct got_error
*
751 read_more_pack_stream(int infd
, BUF
*buf
, size_t minsize
)
753 const struct got_error
*err
= NULL
;
754 uint8_t readahead
[65536];
757 err
= got_poll_read_full(infd
, &have
,
758 readahead
, sizeof(readahead
), minsize
);
762 err
= buf_append(&newlen
, buf
, readahead
, have
);
768 static const struct got_error
*
769 copy_object_type_and_size(uint8_t *type
, uint64_t *size
, int infd
, int outfd
,
770 off_t
*outsize
, BUF
*buf
, size_t *buf_pos
, struct got_hash
*ctx
)
772 const struct got_error
*err
= NULL
;
777 off_t obj_offset
= *outsize
;
780 /* We do not support size values which don't fit in 64 bit. */
782 return got_error_fmt(GOT_ERR_OBJ_TOO_LARGE
,
783 "packfile offset %lld", (long long)obj_offset
);
785 if (buf_len(buf
) - *buf_pos
< sizeof(sizebuf
[0])) {
786 err
= read_more_pack_stream(infd
, buf
,
792 sizebuf
[i
] = buf_getc(buf
, *buf_pos
);
793 *buf_pos
+= sizeof(sizebuf
[i
]);
796 t
= (sizebuf
[i
] & GOT_PACK_OBJ_SIZE0_TYPE_MASK
) >>
797 GOT_PACK_OBJ_SIZE0_TYPE_MASK_SHIFT
;
798 s
= (sizebuf
[i
] & GOT_PACK_OBJ_SIZE0_VAL_MASK
);
800 size_t shift
= 4 + 7 * (i
- 1);
801 s
|= ((sizebuf
[i
] & GOT_PACK_OBJ_SIZE_VAL_MASK
) <<
805 } while (sizebuf
[i
- 1] & GOT_PACK_OBJ_SIZE_MORE
);
807 err
= got_pack_hwrite(outfd
, sizebuf
, i
, ctx
);
817 static const struct got_error
*
818 copy_ref_delta(int infd
, int outfd
, off_t
*outsize
, BUF
*buf
, size_t *buf_pos
,
819 struct got_hash
*ctx
)
821 const struct got_error
*err
= NULL
;
822 size_t remain
= buf_len(buf
) - *buf_pos
;
824 if (remain
< SHA1_DIGEST_LENGTH
) {
825 err
= read_more_pack_stream(infd
, buf
,
826 SHA1_DIGEST_LENGTH
- remain
);
831 err
= got_pack_hwrite(outfd
, buf_get(buf
) + *buf_pos
,
832 SHA1_DIGEST_LENGTH
, ctx
);
836 *buf_pos
+= SHA1_DIGEST_LENGTH
;
840 static const struct got_error
*
841 copy_offset_delta(int infd
, int outfd
, off_t
*outsize
, BUF
*buf
, size_t *buf_pos
,
842 struct got_hash
*ctx
)
844 const struct got_error
*err
= NULL
;
848 off_t obj_offset
= *outsize
;
851 /* We do not support offset values which don't fit in 64 bit. */
853 return got_error_fmt(GOT_ERR_OBJ_TOO_LARGE
,
854 "packfile offset %lld", (long long)obj_offset
);
856 if (buf_len(buf
) - *buf_pos
< sizeof(offbuf
[0])) {
857 err
= read_more_pack_stream(infd
, buf
,
863 offbuf
[i
] = buf_getc(buf
, *buf_pos
);
864 *buf_pos
+= sizeof(offbuf
[i
]);
867 o
= (offbuf
[i
] & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK
);
871 o
+= (offbuf
[i
] & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK
);
874 } while (offbuf
[i
- 1] & GOT_PACK_OBJ_DELTA_OFF_MORE
);
876 if (o
< sizeof(struct got_packfile_hdr
) || o
> *outsize
)
877 return got_error(GOT_ERR_PACK_OFFSET
);
879 err
= got_pack_hwrite(outfd
, offbuf
, i
, ctx
);
887 static const struct got_error
*
888 copy_zstream(int infd
, int outfd
, off_t
*outsize
, BUF
*buf
, size_t *buf_pos
,
889 struct got_hash
*ctx
)
891 const struct got_error
*err
= NULL
;
895 size_t consumed_total
= 0;
896 off_t zstream_offset
= *outsize
;
898 memset(&z
, 0, sizeof(z
));
902 zret
= inflateInit(&z
);
905 return got_error_from_errno("inflateInit");
906 if (zret
== Z_MEM_ERROR
) {
908 return got_error_from_errno("inflateInit");
910 return got_error_msg(GOT_ERR_DECOMPRESSION
,
911 "inflateInit failed");
914 while (zret
!= Z_STREAM_END
) {
915 size_t last_total_in
, consumed
;
918 * Decompress into the void. Object data will be parsed
919 * later, when the pack file is indexed. For now, we just
920 * want to locate the end of the compressed stream.
922 while (zret
!= Z_STREAM_END
&& buf_len(buf
) - *buf_pos
> 0) {
923 last_total_in
= z
.total_in
;
924 z
.next_in
= buf_get(buf
) + *buf_pos
;
925 z
.avail_in
= buf_len(buf
) - *buf_pos
;
926 z
.next_out
= voidbuf
;
927 z
.avail_out
= sizeof(voidbuf
);
929 zret
= inflate(&z
, Z_SYNC_FLUSH
);
930 if (zret
!= Z_OK
&& zret
!= Z_BUF_ERROR
&&
931 zret
!= Z_STREAM_END
) {
932 err
= got_error_fmt(GOT_ERR_DECOMPRESSION
,
933 "packfile offset %lld",
934 (long long)zstream_offset
);
937 consumed
= z
.total_in
- last_total_in
;
939 err
= got_pack_hwrite(outfd
, buf_get(buf
) + *buf_pos
,
944 err
= buf_discard(buf
, *buf_pos
+ consumed
);
949 consumed_total
+= consumed
;
952 if (zret
!= Z_STREAM_END
) {
953 err
= read_more_pack_stream(infd
, buf
, 1);
960 *outsize
+= consumed_total
;
966 static const struct got_error
*
967 validate_object_type(int obj_type
)
970 case GOT_OBJ_TYPE_BLOB
:
971 case GOT_OBJ_TYPE_COMMIT
:
972 case GOT_OBJ_TYPE_TREE
:
973 case GOT_OBJ_TYPE_TAG
:
974 case GOT_OBJ_TYPE_REF_DELTA
:
975 case GOT_OBJ_TYPE_OFFSET_DELTA
:
981 return got_error(GOT_ERR_OBJ_TYPE
);
984 static const struct got_error
*
985 ensure_all_objects_exist_locally(struct gotd_ref_updates
*ref_updates
)
987 const struct got_error
*err
= NULL
;
988 struct gotd_ref_update
*ref_update
;
989 struct got_object
*obj
;
991 STAILQ_FOREACH(ref_update
, ref_updates
, entry
) {
992 err
= got_object_open(&obj
, repo_write
.repo
,
993 &ref_update
->new_id
);
996 got_object_close(obj
);
1002 static const struct got_error
*
1003 recv_packdata(off_t
*outsize
, uint32_t *nobj
, uint8_t *sha1
,
1004 int infd
, int outfd
)
1006 const struct got_error
*err
;
1007 struct repo_write_client
*client
= &repo_write_client
;
1008 struct got_packfile_hdr hdr
;
1011 struct got_hash ctx
;
1012 uint8_t expected_sha1
[SHA1_DIGEST_LENGTH
];
1013 char hex
[SHA1_DIGEST_STRING_LENGTH
];
1015 size_t buf_pos
= 0, remain
;
1021 /* if only deleting references there's nothing to read */
1022 if (client
->nref_updates
== client
->nref_del
)
1025 got_hash_init(&ctx
, GOT_HASH_SHA1
);
1027 err
= got_poll_read_full(infd
, &have
, &hdr
, sizeof(hdr
), sizeof(hdr
));
1030 if (have
!= sizeof(hdr
))
1031 return got_error_msg(GOT_ERR_BAD_PACKFILE
, "short pack file");
1034 if (hdr
.signature
!= htobe32(GOT_PACKFILE_SIGNATURE
))
1035 return got_error_msg(GOT_ERR_BAD_PACKFILE
,
1036 "bad packfile signature");
1037 if (hdr
.version
!= htobe32(GOT_PACKFILE_VERSION
))
1038 return got_error_msg(GOT_ERR_BAD_PACKFILE
,
1039 "bad packfile version");
1041 *nobj
= be32toh(hdr
.nobjects
);
1044 * Clients which are creating new references only
1045 * will send us an empty pack file.
1047 if (client
->nref_updates
> 0 &&
1048 client
->nref_updates
== client
->nref_new
)
1052 * Clients which only move existing refs will send us an empty
1053 * pack file. All referenced objects must exist locally.
1055 err
= ensure_all_objects_exist_locally(&client
->ref_updates
);
1057 if (err
->code
!= GOT_ERR_NO_OBJ
)
1059 return got_error_msg(GOT_ERR_BAD_PACKFILE
,
1060 "bad packfile with zero objects");
1063 client
->nref_move
= client
->nref_updates
;
1067 log_debug("expecting %d objects", *nobj
);
1069 err
= got_pack_hwrite(outfd
, &hdr
, sizeof(hdr
), &ctx
);
1073 err
= buf_alloc(&buf
, 65536);
1077 while (nhave
!= *nobj
) {
1081 err
= copy_object_type_and_size(&obj_type
, &obj_size
,
1082 infd
, outfd
, outsize
, buf
, &buf_pos
, &ctx
);
1086 err
= validate_object_type(obj_type
);
1090 if (obj_type
== GOT_OBJ_TYPE_REF_DELTA
) {
1091 err
= copy_ref_delta(infd
, outfd
, outsize
,
1092 buf
, &buf_pos
, &ctx
);
1095 } else if (obj_type
== GOT_OBJ_TYPE_OFFSET_DELTA
) {
1096 err
= copy_offset_delta(infd
, outfd
, outsize
,
1097 buf
, &buf_pos
, &ctx
);
1102 err
= copy_zstream(infd
, outfd
, outsize
, buf
, &buf_pos
, &ctx
);
1109 log_debug("received %u objects", *nobj
);
1111 got_hash_final(&ctx
, expected_sha1
);
1113 remain
= buf_len(buf
) - buf_pos
;
1114 if (remain
< SHA1_DIGEST_LENGTH
) {
1115 err
= read_more_pack_stream(infd
, buf
,
1116 SHA1_DIGEST_LENGTH
- remain
);
1121 got_sha1_digest_to_str(expected_sha1
, hex
, sizeof(hex
));
1122 log_debug("expect SHA1: %s", hex
);
1123 got_sha1_digest_to_str(buf_get(buf
) + buf_pos
, hex
, sizeof(hex
));
1124 log_debug("actual SHA1: %s", hex
);
1126 if (memcmp(buf_get(buf
) + buf_pos
, expected_sha1
,
1127 SHA1_DIGEST_LENGTH
) != 0) {
1128 err
= got_error(GOT_ERR_PACKFILE_CSUM
);
1132 memcpy(sha1
, expected_sha1
, SHA1_DIGEST_LENGTH
);
1134 w
= write(outfd
, expected_sha1
, SHA1_DIGEST_LENGTH
);
1136 err
= got_error_from_errno("write");
1139 if (w
!= SHA1_DIGEST_LENGTH
) {
1140 err
= got_error(GOT_ERR_IO
);
1144 *outsize
+= SHA1_DIGEST_LENGTH
;
1146 if (fsync(outfd
) == -1) {
1147 err
= got_error_from_errno("fsync");
1150 if (lseek(outfd
, 0L, SEEK_SET
) == -1) {
1151 err
= got_error_from_errno("lseek");
1159 static const struct got_error
*
1160 report_pack_status(const struct got_error
*unpack_err
)
1162 const struct got_error
*err
= NULL
;
1163 struct repo_write_client
*client
= &repo_write_client
;
1164 struct gotd_imsg_packfile_status istatus
;
1166 struct imsgbuf ibuf
;
1167 const char *unpack_ok
= "unpack ok\n";
1170 if (imsgbuf_init(&ibuf
, client
->fd
))
1171 return got_error_from_errno("imsgbuf_init");
1172 imsgbuf_allow_fdpass(&ibuf
);
1175 istatus
.reason_len
= strlen(unpack_err
->msg
);
1177 istatus
.reason_len
= strlen(unpack_ok
);
1179 len
= sizeof(istatus
) + istatus
.reason_len
;
1180 wbuf
= imsg_create(&ibuf
, GOTD_IMSG_PACKFILE_STATUS
, PROC_REPO_WRITE
,
1181 repo_write
.pid
, len
);
1183 err
= got_error_from_errno("imsg_create PACKFILE_STATUS");
1187 if (imsg_add(wbuf
, &istatus
, sizeof(istatus
)) == -1) {
1188 err
= got_error_from_errno("imsg_add PACKFILE_STATUS");
1192 if (imsg_add(wbuf
, err
? err
->msg
: unpack_ok
,
1193 istatus
.reason_len
) == -1) {
1194 err
= got_error_from_errno("imsg_add PACKFILE_STATUS");
1198 imsg_close(&ibuf
, wbuf
);
1200 err
= gotd_imsg_flush(&ibuf
);
1202 imsgbuf_clear(&ibuf
);
1206 static const struct got_error
*
1207 recv_packfile(int *have_packfile
, struct imsg
*imsg
)
1209 const struct got_error
*err
= NULL
, *unpack_err
;
1210 struct repo_write_client
*client
= &repo_write_client
;
1211 struct gotd_imsg_recv_packfile ireq
;
1212 struct got_object_id id
;
1213 FILE *tempfiles
[3] = { NULL
, NULL
, NULL
};
1214 struct repo_tempfile
{
1217 } repo_tempfiles
[3] = { { - 1, - 1 }, { - 1, - 1 }, { - 1, - 1 }, };
1220 struct got_ratelimit rl
;
1221 struct got_pack
*pack
= NULL
;
1222 off_t pack_filesize
= 0;
1225 log_debug("packfile request received");
1228 got_ratelimit_init(&rl
, 2, 0);
1230 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1231 if (datalen
!= sizeof(ireq
))
1232 return got_error(GOT_ERR_PRIVSEP_LEN
);
1233 memcpy(&ireq
, imsg
->data
, sizeof(ireq
));
1235 if (client
->pack_pipe
== -1 || client
->packidx_fd
== -1)
1236 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
1238 pack
= &client
->pack
;
1239 memset(pack
, 0, sizeof(*pack
));
1240 pack
->fd
= imsg_get_fd(imsg
);
1241 if (pack
->fd
== -1) {
1242 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
1246 err
= got_delta_cache_alloc(&pack
->delta_cache
);
1250 for (i
= 0; i
< nitems(repo_tempfiles
); i
++) {
1251 struct repo_tempfile
*t
= &repo_tempfiles
[i
];
1252 err
= got_repo_temp_fds_get(&t
->fd
, &t
->idx
, repo_write
.repo
);
1257 for (i
= 0; i
< nitems(tempfiles
); i
++) {
1261 fd
= dup(repo_tempfiles
[i
].fd
);
1263 err
= got_error_from_errno("dup");
1266 f
= fdopen(fd
, "w+");
1268 err
= got_error_from_errno("fdopen");
1275 log_debug("receiving pack data");
1276 unpack_err
= recv_packdata(&pack_filesize
, &nobj
,
1277 client
->pack_sha1
, client
->pack_pipe
, pack
->fd
);
1278 if (ireq
.report_status
) {
1279 err
= report_pack_status(unpack_err
);
1281 /* Git clients hang up after sending the pack file. */
1282 if (err
->code
== GOT_ERR_EOF
)
1291 log_debug("pack data received");
1294 * Clients which are creating new references only will
1295 * send us an empty pack file.
1298 pack_filesize
== sizeof(struct got_packfile_hdr
) &&
1299 client
->nref_updates
> 0 &&
1300 client
->nref_updates
== client
->nref_new
)
1304 * Clients which are deleting references only will send
1308 client
->nref_del
> 0 &&
1309 client
->nref_updates
== client
->nref_del
)
1313 * Clients which only move existing refs will send us an empty
1314 * pack file. All referenced objects must exist locally.
1317 pack_filesize
== sizeof(struct got_packfile_hdr
) &&
1318 client
->nref_move
> 0 &&
1319 client
->nref_updates
== client
->nref_move
)
1322 pack
->filesize
= pack_filesize
;
1325 memset(&id
, 0, sizeof(id
));
1326 memcpy(&id
.hash
, client
->pack_sha1
, SHA1_DIGEST_LENGTH
);
1327 id
.algo
= GOT_HASH_SHA1
;
1329 log_debug("begin indexing pack (%lld bytes in size)",
1330 (long long)pack
->filesize
);
1331 err
= got_pack_index(pack
, client
->packidx_fd
,
1332 tempfiles
[0], tempfiles
[1], tempfiles
[2], &id
,
1333 pack_index_progress
, NULL
, &rl
);
1336 log_debug("done indexing pack");
1338 if (fsync(client
->packidx_fd
) == -1) {
1339 err
= got_error_from_errno("fsync");
1342 if (lseek(client
->packidx_fd
, 0L, SEEK_SET
) == -1)
1343 err
= got_error_from_errno("lseek");
1345 if (close(client
->pack_pipe
) == -1 && err
== NULL
)
1346 err
= got_error_from_errno("close");
1347 client
->pack_pipe
= -1;
1348 for (i
= 0; i
< nitems(repo_tempfiles
); i
++) {
1349 struct repo_tempfile
*t
= &repo_tempfiles
[i
];
1351 got_repo_temp_fds_put(t
->idx
, repo_write
.repo
);
1353 for (i
= 0; i
< nitems(tempfiles
); i
++) {
1354 if (tempfiles
[i
] && fclose(tempfiles
[i
]) == EOF
&& err
== NULL
)
1355 err
= got_error_from_errno("fclose");
1358 got_pack_close(pack
);
1362 static const struct got_error
*
1363 verify_packfile(void)
1365 const struct got_error
*err
= NULL
, *close_err
;
1366 struct repo_write_client
*client
= &repo_write_client
;
1367 struct gotd_ref_update
*ref_update
;
1368 struct got_packidx
*packidx
= NULL
;
1370 char *id_str
= NULL
;
1371 struct got_object
*obj
= NULL
;
1372 struct got_pathlist_entry
*pe
;
1373 char hex
[SHA1_DIGEST_STRING_LENGTH
];
1375 if (STAILQ_EMPTY(&client
->ref_updates
)) {
1376 return got_error_msg(GOT_ERR_BAD_REQUEST
,
1377 "cannot verify pack file without any ref-updates");
1380 if (client
->pack
.fd
== -1) {
1381 return got_error_msg(GOT_ERR_BAD_REQUEST
,
1382 "invalid pack file handle during pack verification");
1384 if (client
->packidx_fd
== -1) {
1385 return got_error_msg(GOT_ERR_BAD_REQUEST
,
1386 "invalid pack index handle during pack verification");
1389 if (fstat(client
->packidx_fd
, &sb
) == -1)
1390 return got_error_from_errno("pack index fstat");
1392 packidx
= malloc(sizeof(*packidx
));
1393 memset(packidx
, 0, sizeof(*packidx
));
1394 packidx
->fd
= client
->packidx_fd
;
1395 client
->packidx_fd
= -1;
1396 packidx
->len
= sb
.st_size
;
1398 err
= got_packidx_init_hdr(packidx
, 1, client
->pack
.filesize
);
1402 STAILQ_FOREACH(ref_update
, &client
->ref_updates
, entry
) {
1403 if (ref_update
->delete_ref
)
1406 TAILQ_FOREACH(pe
, repo_write
.protected_tag_namespaces
, entry
) {
1407 err
= protect_tag_namespace(pe
->path
, &client
->pack
,
1408 packidx
, ref_update
);
1414 * Objects which already exist in our repository need
1415 * not be present in the pack file.
1417 err
= got_object_open(&obj
, repo_write
.repo
,
1418 &ref_update
->new_id
);
1419 if (err
&& err
->code
!= GOT_ERR_NO_OBJ
)
1423 got_object_close(obj
);
1426 int idx
= got_packidx_get_object_idx(packidx
,
1427 &ref_update
->new_id
);
1429 got_object_id_hex(&ref_update
->new_id
,
1431 err
= got_error_fmt(GOT_ERR_BAD_PACKFILE
,
1432 "object %s is missing from pack file",
1438 TAILQ_FOREACH(pe
, repo_write
.protected_branch_namespaces
,
1440 err
= protect_branch_namespace(pe
->path
,
1441 &client
->pack
, packidx
, ref_update
);
1445 TAILQ_FOREACH(pe
, repo_write
.protected_branches
, entry
) {
1446 err
= protect_branch(pe
->path
, &client
->pack
,
1447 packidx
, ref_update
);
1454 close_err
= got_packidx_close(packidx
);
1455 if (close_err
&& err
== NULL
)
1459 got_object_close(obj
);
1463 static const struct got_error
*
1464 protect_refs_from_deletion(void)
1466 const struct got_error
*err
= NULL
;
1467 struct repo_write_client
*client
= &repo_write_client
;
1468 struct gotd_ref_update
*ref_update
;
1469 struct got_pathlist_entry
*pe
;
1470 const char *refname
;
1472 STAILQ_FOREACH(ref_update
, &client
->ref_updates
, entry
) {
1473 if (!ref_update
->delete_ref
)
1476 refname
= got_ref_get_name(ref_update
->ref
);
1478 TAILQ_FOREACH(pe
, repo_write
.protected_tag_namespaces
, entry
) {
1479 err
= protect_ref_namespace(refname
, pe
->path
);
1484 TAILQ_FOREACH(pe
, repo_write
.protected_branch_namespaces
,
1486 err
= protect_ref_namespace(refname
, pe
->path
);
1491 TAILQ_FOREACH(pe
, repo_write
.protected_branches
, entry
) {
1492 if (strcmp(refname
, pe
->path
) == 0) {
1493 return got_error_fmt(GOT_ERR_REF_PROTECTED
,
1502 static const struct got_error
*
1503 install_packfile(struct gotd_imsgev
*iev
)
1505 struct repo_write_client
*client
= &repo_write_client
;
1506 struct gotd_imsg_packfile_install inst
;
1509 memset(&inst
, 0, sizeof(inst
));
1510 memcpy(inst
.pack_sha1
, client
->pack_sha1
, SHA1_DIGEST_LENGTH
);
1512 ret
= gotd_imsg_compose_event(iev
, GOTD_IMSG_PACKFILE_INSTALL
,
1513 PROC_REPO_WRITE
, -1, &inst
, sizeof(inst
));
1515 return got_error_from_errno("imsg_compose PACKFILE_INSTALL");
1520 static const struct got_error
*
1521 send_ref_updates_start(int nref_updates
, struct gotd_imsgev
*iev
)
1523 struct gotd_imsg_ref_updates_start istart
;
1526 memset(&istart
, 0, sizeof(istart
));
1527 istart
.nref_updates
= nref_updates
;
1529 ret
= gotd_imsg_compose_event(iev
, GOTD_IMSG_REF_UPDATES_START
,
1530 PROC_REPO_WRITE
, -1, &istart
, sizeof(istart
));
1532 return got_error_from_errno("imsg_compose REF_UPDATES_START");
1538 static const struct got_error
*
1539 send_ref_update(struct gotd_ref_update
*ref_update
, struct gotd_imsgev
*iev
)
1541 struct gotd_imsg_ref_update iref
;
1542 const char *refname
= got_ref_get_name(ref_update
->ref
);
1546 memset(&iref
, 0, sizeof(iref
));
1547 memcpy(iref
.old_id
, ref_update
->old_id
.hash
, SHA1_DIGEST_LENGTH
);
1548 memcpy(iref
.new_id
, ref_update
->new_id
.hash
, SHA1_DIGEST_LENGTH
);
1549 iref
.ref_is_new
= ref_update
->ref_is_new
;
1550 iref
.delete_ref
= ref_update
->delete_ref
;
1551 iref
.name_len
= strlen(refname
);
1553 len
= sizeof(iref
) + iref
.name_len
;
1554 wbuf
= imsg_create(&iev
->ibuf
, GOTD_IMSG_REF_UPDATE
, PROC_REPO_WRITE
,
1555 repo_write
.pid
, len
);
1557 return got_error_from_errno("imsg_create REF_UPDATE");
1559 if (imsg_add(wbuf
, &iref
, sizeof(iref
)) == -1)
1560 return got_error_from_errno("imsg_add REF_UPDATE");
1561 if (imsg_add(wbuf
, refname
, iref
.name_len
) == -1)
1562 return got_error_from_errno("imsg_add REF_UPDATE");
1564 imsg_close(&iev
->ibuf
, wbuf
);
1566 gotd_imsg_event_add(iev
);
1570 static const struct got_error
*
1571 update_refs(struct gotd_imsgev
*iev
)
1573 const struct got_error
*err
= NULL
;
1574 struct repo_write_client
*client
= &repo_write_client
;
1575 struct gotd_ref_update
*ref_update
;
1577 err
= send_ref_updates_start(client
->nref_updates
, iev
);
1581 STAILQ_FOREACH(ref_update
, &client
->ref_updates
, entry
) {
1582 err
= send_ref_update(ref_update
, iev
);
1590 static const struct got_error
*
1591 receive_pack_pipe(struct imsg
*imsg
, struct gotd_imsgev
*iev
)
1593 struct repo_write_client
*client
= &repo_write_client
;
1596 log_debug("receiving pack pipe descriptor");
1598 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1600 return got_error(GOT_ERR_PRIVSEP_LEN
);
1602 if (client
->pack_pipe
!= -1)
1603 return got_error(GOT_ERR_PRIVSEP_MSG
);
1605 client
->pack_pipe
= imsg_get_fd(imsg
);
1606 if (client
->pack_pipe
== -1)
1607 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
1612 static const struct got_error
*
1613 receive_pack_idx(struct imsg
*imsg
, struct gotd_imsgev
*iev
)
1615 struct repo_write_client
*client
= &repo_write_client
;
1618 log_debug("receiving pack index output file");
1620 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1622 return got_error(GOT_ERR_PRIVSEP_LEN
);
1624 if (client
->packidx_fd
!= -1)
1625 return got_error(GOT_ERR_PRIVSEP_MSG
);
1627 client
->packidx_fd
= imsg_get_fd(imsg
);
1628 if (client
->packidx_fd
== -1)
1629 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
1634 static const struct got_error
*
1635 notify_removed_ref(const char *refname
, struct got_object_id
*id
,
1636 struct gotd_imsgev
*iev
, int fd
)
1638 const struct got_error
*err
;
1641 err
= got_object_id_str(&id_str
, id
);
1645 dprintf(fd
, "Removed %s: %s\n", refname
, id_str
);
1651 format_author(char *author
)
1655 smallerthan
= strchr(author
, '<');
1656 if (smallerthan
&& smallerthan
[1] != '\0')
1657 author
= smallerthan
+ 1;
1658 author
[strcspn(author
, "@>")] = '\0';
1663 static const struct got_error
*
1664 print_commit_oneline(struct got_commit_object
*commit
, struct got_object_id
*id
,
1665 struct got_repository
*repo
, int fd
)
1667 const struct got_error
*err
= NULL
;
1668 char *id_str
= NULL
, *logmsg0
= NULL
;
1670 char *committer
= NULL
, *author
= NULL
;
1671 time_t committer_time
;
1673 err
= got_object_id_str(&id_str
, id
);
1677 committer_time
= got_object_commit_get_committer_time(commit
);
1679 err
= got_object_commit_get_logmsg(&logmsg0
, commit
);
1684 while (isspace((unsigned char)s
[0]))
1687 nl
= strchr(s
, '\n');
1692 if (strcmp(got_object_commit_get_author(commit
),
1693 got_object_commit_get_committer(commit
)) != 0) {
1694 author
= strdup(got_object_commit_get_author(commit
));
1695 if (author
== NULL
) {
1696 err
= got_error_from_errno("strdup");
1699 dprintf(fd
, "%lld %.7s %.8s %s\n", (long long)committer_time
,
1700 id_str
, format_author(author
), s
);
1702 committer
= strdup(got_object_commit_get_committer(commit
));
1703 dprintf(fd
, "%lld %.7s %.8s %s\n", (long long)committer_time
,
1704 id_str
, format_author(committer
), s
);
1707 if (fsync(fd
) == -1 && err
== NULL
)
1708 err
= got_error_from_errno("fsync");
1717 static const struct got_error
*
1718 print_diffstat(struct got_diffstat_cb_arg
*dsa
, int fd
)
1720 struct got_pathlist_entry
*pe
;
1722 TAILQ_FOREACH(pe
, dsa
->paths
, entry
) {
1723 struct got_diff_changed_path
*cp
= pe
->data
;
1724 int pad
= dsa
->max_path_len
- pe
->path_len
+ 1;
1726 dprintf(fd
, " %c %s%*c | %*d+ %*d-\n", cp
->status
,
1727 pe
->path
, pad
, ' ', dsa
->add_cols
+ 1, cp
->add
,
1728 dsa
->rm_cols
+ 1, cp
->rm
);
1731 "\n%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n\n",
1732 dsa
->nfiles
, dsa
->nfiles
> 1 ? "s" : "", dsa
->ins
,
1733 dsa
->ins
!= 1 ? "s" : "", dsa
->del
, dsa
->del
!= 1 ? "s" : "");
1738 static const struct got_error
*
1739 print_commit(struct got_commit_object
*commit
, struct got_object_id
*id
,
1740 struct got_repository
*repo
, struct got_pathlist_head
*changed_paths
,
1741 struct got_diffstat_cb_arg
*diffstat
, int fd
)
1743 const struct got_error
*err
= NULL
;
1744 char *id_str
, *logmsg0
, *logmsg
, *line
;
1745 time_t committer_time
;
1746 const char *author
, *committer
;
1748 err
= got_object_id_str(&id_str
, id
);
1752 dprintf(fd
, "commit %s\n", id_str
);
1755 dprintf(fd
, "from: %s\n", got_object_commit_get_author(commit
));
1756 author
= got_object_commit_get_author(commit
);
1757 committer
= got_object_commit_get_committer(commit
);
1758 if (strcmp(author
, committer
) != 0)
1759 dprintf(fd
, "via: %s\n", committer
);
1760 committer_time
= got_object_commit_get_committer_time(commit
);
1761 dprintf(fd
, "date: %lld\n", (long long)committer_time
);
1762 if (got_object_commit_get_nparents(commit
) > 1) {
1763 const struct got_object_id_queue
*parent_ids
;
1764 struct got_object_qid
*qid
;
1766 parent_ids
= got_object_commit_get_parent_ids(commit
);
1767 STAILQ_FOREACH(qid
, parent_ids
, entry
) {
1768 err
= got_object_id_str(&id_str
, &qid
->id
);
1771 dprintf(fd
, "parent %d: %s\n", n
++, id_str
);
1777 err
= got_object_commit_get_logmsg(&logmsg0
, commit
);
1781 dprintf(fd
, "messagelen: %zu\n", strlen(logmsg0
));
1785 line
= strsep(&logmsg
, "\n");
1787 dprintf(fd
, " %s\n", line
);
1791 err
= print_diffstat(diffstat
, fd
);
1795 if (fsync(fd
) == -1 && err
== NULL
)
1796 err
= got_error_from_errno("fsync");
1802 static const struct got_error
*
1803 get_changed_paths(struct got_pathlist_head
*paths
,
1804 struct got_commit_object
*commit
, struct got_repository
*repo
,
1805 struct got_diffstat_cb_arg
*dsa
)
1807 const struct got_error
*err
= NULL
;
1808 struct got_object_id
*tree_id1
= NULL
, *tree_id2
= NULL
;
1809 struct got_tree_object
*tree1
= NULL
, *tree2
= NULL
;
1810 struct got_object_qid
*qid
;
1811 got_diff_blob_cb cb
= got_diff_tree_collect_changed_paths
;
1812 FILE *f1
= repo_write
.diff
.f1
, *f2
= repo_write
.diff
.f2
;
1813 int fd1
= repo_write
.diff
.fd1
, fd2
= repo_write
.diff
.fd2
;
1816 cb
= got_diff_tree_compute_diffstat
;
1818 err
= got_opentemp_truncate(f1
);
1821 err
= got_opentemp_truncate(f2
);
1824 err
= got_opentemp_truncatefd(fd1
);
1827 err
= got_opentemp_truncatefd(fd2
);
1831 qid
= STAILQ_FIRST(got_object_commit_get_parent_ids(commit
));
1833 struct got_commit_object
*pcommit
;
1834 err
= got_object_open_as_commit(&pcommit
, repo
,
1839 tree_id1
= got_object_id_dup(
1840 got_object_commit_get_tree_id(pcommit
));
1841 if (tree_id1
== NULL
) {
1842 got_object_commit_close(pcommit
);
1843 return got_error_from_errno("got_object_id_dup");
1845 got_object_commit_close(pcommit
);
1850 err
= got_object_open_as_tree(&tree1
, repo
, tree_id1
);
1855 tree_id2
= got_object_commit_get_tree_id(commit
);
1856 err
= got_object_open_as_tree(&tree2
, repo
, tree_id2
);
1860 err
= got_diff_tree(tree1
, tree2
, f1
, f2
, fd1
, fd2
, "", "", repo
,
1861 cb
, dsa
? (void *)dsa
: paths
, dsa
? 1 : 0);
1864 got_object_tree_close(tree1
);
1866 got_object_tree_close(tree2
);
1871 static const struct got_error
*
1872 print_commits(struct got_object_id
*root_id
, struct got_object_id
*end_id
,
1873 struct got_repository
*repo
, int fd
)
1875 const struct got_error
*err
;
1876 struct got_commit_graph
*graph
;
1877 struct got_object_id_queue reversed_commits
;
1878 struct got_object_qid
*qid
;
1879 struct got_commit_object
*commit
= NULL
;
1880 struct got_pathlist_head changed_paths
;
1882 const int shortlog_threshold
= 50;
1884 STAILQ_INIT(&reversed_commits
);
1885 TAILQ_INIT(&changed_paths
);
1887 /* XXX first-parent only for now */
1888 err
= got_commit_graph_open(&graph
, "/", 1);
1891 err
= got_commit_graph_bfsort(graph
, root_id
, repo
,
1892 check_cancelled
, NULL
);
1896 struct got_object_id id
;
1898 err
= got_commit_graph_iter_next(&id
, graph
, repo
,
1899 check_cancelled
, NULL
);
1901 if (err
->code
== GOT_ERR_ITER_COMPLETED
)
1906 err
= got_object_open_as_commit(&commit
, repo
, &id
);
1910 if (end_id
&& got_object_id_cmp(&id
, end_id
) == 0)
1913 err
= got_object_qid_alloc(&qid
, &id
);
1917 STAILQ_INSERT_HEAD(&reversed_commits
, qid
, entry
);
1919 got_object_commit_close(commit
);
1925 STAILQ_FOREACH(qid
, &reversed_commits
, entry
) {
1926 struct got_diffstat_cb_arg dsa
= { 0, 0, 0, 0, 0, 0,
1927 &changed_paths
, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE
};
1929 err
= got_object_open_as_commit(&commit
, repo
, &qid
->id
);
1933 if (ncommits
> shortlog_threshold
) {
1934 err
= print_commit_oneline(commit
, &qid
->id
,
1939 err
= get_changed_paths(&changed_paths
, commit
,
1943 err
= print_commit(commit
, &qid
->id
, repo
,
1944 &changed_paths
, &dsa
, fd
);
1946 got_object_commit_close(commit
);
1948 got_pathlist_free(&changed_paths
, GOT_PATHLIST_FREE_ALL
);
1952 got_object_commit_close(commit
);
1953 while (!STAILQ_EMPTY(&reversed_commits
)) {
1954 qid
= STAILQ_FIRST(&reversed_commits
);
1955 STAILQ_REMOVE_HEAD(&reversed_commits
, entry
);
1956 got_object_qid_free(qid
);
1958 got_pathlist_free(&changed_paths
, GOT_PATHLIST_FREE_ALL
);
1959 got_commit_graph_close(graph
);
1963 static const struct got_error
*
1964 print_tag(struct got_object_id
*id
,
1965 const char *refname
, struct got_repository
*repo
, int fd
)
1967 const struct got_error
*err
= NULL
;
1968 struct got_tag_object
*tag
= NULL
;
1969 const char *tagger
= NULL
;
1970 char *id_str
= NULL
, *tagmsg0
= NULL
, *tagmsg
, *line
;
1973 err
= got_object_open_as_tag(&tag
, repo
, id
);
1977 tagger
= got_object_tag_get_tagger(tag
);
1978 tagger_time
= got_object_tag_get_tagger_time(tag
);
1979 err
= got_object_id_str(&id_str
,
1980 got_object_tag_get_object_id(tag
));
1984 dprintf(fd
, "tag %s\n", refname
);
1985 dprintf(fd
, "from: %s\n", tagger
);
1986 dprintf(fd
, "date: %lld\n", (long long)tagger_time
);
1988 switch (got_object_tag_get_object_type(tag
)) {
1989 case GOT_OBJ_TYPE_BLOB
:
1990 dprintf(fd
, "object: %s %s\n", GOT_OBJ_LABEL_BLOB
, id_str
);
1992 case GOT_OBJ_TYPE_TREE
:
1993 dprintf(fd
, "object: %s %s\n", GOT_OBJ_LABEL_TREE
, id_str
);
1995 case GOT_OBJ_TYPE_COMMIT
:
1996 dprintf(fd
, "object: %s %s\n", GOT_OBJ_LABEL_COMMIT
, id_str
);
1998 case GOT_OBJ_TYPE_TAG
:
1999 dprintf(fd
, "object: %s %s\n", GOT_OBJ_LABEL_TAG
, id_str
);
2005 tagmsg0
= strdup(got_object_tag_get_message(tag
));
2006 if (tagmsg0
== NULL
) {
2007 err
= got_error_from_errno("strdup");
2011 dprintf(fd
, "messagelen: %zu\n", strlen(tagmsg0
));
2015 line
= strsep(&tagmsg
, "\n");
2017 dprintf(fd
, " %s\n", line
);
2022 got_object_tag_close(tag
);
2027 static const struct got_error
*
2028 notify_changed_ref(const char *refname
, struct got_object_id
*old_id
,
2029 struct got_object_id
*new_id
, struct gotd_imsgev
*iev
, int fd
)
2031 const struct got_error
*err
;
2032 int old_obj_type
, new_obj_type
;
2034 char *new_id_str
= NULL
;
2036 err
= got_object_get_type(&old_obj_type
, repo_write
.repo
, old_id
);
2040 err
= got_object_get_type(&new_obj_type
, repo_write
.repo
, new_id
);
2044 switch (new_obj_type
) {
2045 case GOT_OBJ_TYPE_COMMIT
:
2046 err
= print_commits(new_id
,
2047 old_obj_type
== GOT_OBJ_TYPE_COMMIT
? old_id
: NULL
,
2048 repo_write
.repo
, fd
);
2050 case GOT_OBJ_TYPE_TAG
:
2051 err
= print_tag(new_id
, refname
, repo_write
.repo
, fd
);
2054 err
= got_object_type_label(&label
, new_obj_type
);
2057 err
= got_object_id_str(&new_id_str
, new_id
);
2060 dprintf(fd
, "%s: %s object %s\n", refname
, label
, new_id_str
);
2068 static const struct got_error
*
2069 notify_created_ref(const char *refname
, struct got_object_id
*id
,
2070 struct gotd_imsgev
*iev
, int fd
)
2072 const struct got_error
*err
;
2075 err
= got_object_get_type(&obj_type
, repo_write
.repo
, id
);
2079 if (obj_type
== GOT_OBJ_TYPE_TAG
)
2080 return print_tag(id
, refname
, repo_write
.repo
, fd
);
2082 return print_commits(id
, NULL
, repo_write
.repo
, fd
);
2085 static const struct got_error
*
2086 render_notification(struct imsg
*imsg
, struct gotd_imsgev
*iev
)
2088 const struct got_error
*err
= NULL
;
2089 struct gotd_imsg_notification_content ireq
;
2090 size_t datalen
, len
;
2091 char *refname
= NULL
;
2095 fd
= imsg_get_fd(imsg
);
2097 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
2099 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
2100 if (datalen
< sizeof(ireq
)) {
2101 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
2105 memcpy(&ireq
, imsg
->data
, sizeof(ireq
));
2107 if (datalen
!= sizeof(ireq
) + ireq
.refname_len
) {
2108 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
2112 refname
= strndup(imsg
->data
+ sizeof(ireq
), ireq
.refname_len
);
2113 if (refname
== NULL
) {
2114 err
= got_error_from_errno("strndup");
2118 switch (ireq
.action
) {
2119 case GOTD_NOTIF_ACTION_CREATED
:
2120 err
= notify_created_ref(refname
, &ireq
.new_id
, iev
, fd
);
2122 case GOTD_NOTIF_ACTION_REMOVED
:
2123 err
= notify_removed_ref(refname
, &ireq
.old_id
, iev
, fd
);
2125 case GOTD_NOTIF_ACTION_CHANGED
:
2126 err
= notify_changed_ref(refname
, &ireq
.old_id
, &ireq
.new_id
,
2133 if (fsync(fd
) == -1) {
2134 err
= got_error_from_errno("fsync");
2138 len
= sizeof(ireq
) + ireq
.refname_len
;
2139 wbuf
= imsg_create(&iev
->ibuf
, GOTD_IMSG_NOTIFY
, PROC_REPO_WRITE
,
2140 repo_write
.pid
, len
);
2142 err
= got_error_from_errno("imsg_create REF");
2145 if (imsg_add(wbuf
, &ireq
, sizeof(ireq
)) == -1) {
2146 err
= got_error_from_errno("imsg_add NOTIFY");
2149 if (imsg_add(wbuf
, refname
, ireq
.refname_len
) == -1) {
2150 err
= got_error_from_errno("imsg_add NOTIFY");
2154 imsg_close(&iev
->ibuf
, wbuf
);
2155 gotd_imsg_event_add(iev
);
2158 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
2159 err
= got_error_from_errno("close");
2164 repo_write_dispatch_session(int fd
, short event
, void *arg
)
2166 const struct got_error
*err
= NULL
;
2167 struct gotd_imsgev
*iev
= arg
;
2168 struct imsgbuf
*ibuf
= &iev
->ibuf
;
2170 struct repo_write_client
*client
= &repo_write_client
;
2172 int shut
= 0, have_packfile
= 0;
2174 if (event
& EV_READ
) {
2175 if ((n
= imsgbuf_read(ibuf
)) == -1)
2176 fatal("imsg_read error");
2177 if (n
== 0) /* Connection closed. */
2181 if (event
& EV_WRITE
) {
2182 err
= gotd_imsg_flush(ibuf
);
2184 fatalx("%s", err
->msg
);
2188 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
2189 fatal("%s: imsg_get error", __func__
);
2190 if (n
== 0) /* No more messages. */
2193 if (imsg
.hdr
.type
!= GOTD_IMSG_LIST_REFS_INTERNAL
&&
2194 !repo_write
.refs_listed
) {
2195 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2199 switch (imsg
.hdr
.type
) {
2200 case GOTD_IMSG_LIST_REFS_INTERNAL
:
2201 err
= list_refs(&imsg
);
2203 log_warnx("ls-refs: %s", err
->msg
);
2205 case GOTD_IMSG_REF_UPDATE
:
2206 err
= recv_ref_update(&imsg
);
2208 log_warnx("ref-update: %s", err
->msg
);
2210 case GOTD_IMSG_PACKFILE_PIPE
:
2211 err
= receive_pack_pipe(&imsg
, iev
);
2213 log_warnx("receiving pack pipe: %s", err
->msg
);
2217 case GOTD_IMSG_PACKIDX_FILE
:
2218 err
= receive_pack_idx(&imsg
, iev
);
2220 log_warnx("receiving pack index: %s",
2225 case GOTD_IMSG_RECV_PACKFILE
:
2226 err
= protect_refs_from_deletion();
2229 err
= recv_packfile(&have_packfile
, &imsg
);
2231 log_warnx("receive packfile: %s", err
->msg
);
2234 if (have_packfile
) {
2235 err
= verify_packfile();
2237 log_warnx("verify packfile: %s",
2241 err
= install_packfile(iev
);
2243 log_warnx("install packfile: %s",
2248 * Ensure we re-read the pack index list
2251 repo_write
.repo
->pack_path_mtime
.tv_sec
= 0;
2252 repo_write
.repo
->pack_path_mtime
.tv_nsec
= 0;
2254 err
= update_refs(iev
);
2256 log_warnx("update refs: %s", err
->msg
);
2259 case GOTD_IMSG_NOTIFY
:
2260 err
= render_notification(&imsg
, iev
);
2262 log_warnx("render notification: %s", err
->msg
);
2267 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
2274 if (!shut
&& check_cancelled(NULL
) == NULL
) {
2276 gotd_imsg_send_error_event(iev
, PROC_REPO_WRITE
,
2277 client
->id
, err
) == -1) {
2278 log_warnx("could not send error to parent: %s",
2281 gotd_imsg_event_add(iev
);
2283 /* This pipe is dead. Remove its event handler */
2284 event_del(&iev
->ev
);
2285 event_loopexit(NULL
);
2289 static const struct got_error
*
2290 recv_connect(struct imsg
*imsg
)
2292 struct gotd_imsgev
*iev
= &repo_write
.session_iev
;
2295 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
2297 return got_error(GOT_ERR_PRIVSEP_LEN
);
2299 if (repo_write
.session_fd
!= -1)
2300 return got_error(GOT_ERR_PRIVSEP_MSG
);
2302 repo_write
.session_fd
= imsg_get_fd(imsg
);
2303 if (repo_write
.session_fd
== -1)
2304 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
2306 if (imsgbuf_init(&iev
->ibuf
, repo_write
.session_fd
) == -1)
2307 return got_error_from_errno("imsgbuf_init");
2308 imsgbuf_allow_fdpass(&iev
->ibuf
);
2309 iev
->handler
= repo_write_dispatch_session
;
2310 iev
->events
= EV_READ
;
2311 iev
->handler_arg
= NULL
;
2312 event_set(&iev
->ev
, iev
->ibuf
.fd
, EV_READ
,
2313 repo_write_dispatch_session
, iev
);
2314 gotd_imsg_event_add(iev
);
2320 repo_write_dispatch(int fd
, short event
, void *arg
)
2322 const struct got_error
*err
= NULL
;
2323 struct gotd_imsgev
*iev
= arg
;
2324 struct imsgbuf
*ibuf
= &iev
->ibuf
;
2328 struct repo_write_client
*client
= &repo_write_client
;
2330 if (event
& EV_READ
) {
2331 if ((n
= imsgbuf_read(ibuf
)) == -1)
2332 fatal("imsg_read error");
2333 if (n
== 0) { /* Connection closed. */
2339 if (event
& EV_WRITE
) {
2340 err
= gotd_imsg_flush(ibuf
);
2342 fatalx("%s", err
->msg
);
2345 while (err
== NULL
) {
2346 err
= check_cancelled(NULL
);
2349 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
2350 fatal("%s: imsg_get", __func__
);
2351 if (n
== 0) /* No more messages. */
2354 switch (imsg
.hdr
.type
) {
2355 case GOTD_IMSG_CONNECT_REPO_CHILD
:
2356 err
= recv_connect(&imsg
);
2359 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
2360 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2367 if (err
&& gotd_imsg_send_error_event(iev
, PROC_REPO_WRITE
,
2368 client
->id
, err
) == -1)
2369 log_warnx("could not send error to parent: %s", err
->msg
);
2372 gotd_imsg_event_add(iev
);
2374 /* This pipe is dead. Remove its event handler */
2375 event_del(&iev
->ev
);
2376 event_loopexit(NULL
);
2381 repo_write_main(const char *title
, const char *repo_path
,
2382 int *pack_fds
, int *temp_fds
,
2383 FILE *diff_f1
, FILE *diff_f2
, int diff_fd1
, int diff_fd2
,
2384 struct got_pathlist_head
*protected_tag_namespaces
,
2385 struct got_pathlist_head
*protected_branch_namespaces
,
2386 struct got_pathlist_head
*protected_branches
)
2388 const struct got_error
*err
= NULL
;
2389 struct repo_write_client
*client
= &repo_write_client
;
2390 struct gotd_imsgev iev
;
2393 client
->pack_pipe
= -1;
2394 client
->packidx_fd
= -1;
2395 client
->pack
.fd
= -1;
2397 repo_write
.title
= title
;
2398 repo_write
.pid
= getpid();
2399 repo_write
.pack_fds
= pack_fds
;
2400 repo_write
.temp_fds
= temp_fds
;
2401 repo_write
.session_fd
= -1;
2402 repo_write
.session_iev
.ibuf
.fd
= -1;
2403 repo_write
.protected_tag_namespaces
= protected_tag_namespaces
;
2404 repo_write
.protected_branch_namespaces
= protected_branch_namespaces
;
2405 repo_write
.protected_branches
= protected_branches
;
2406 repo_write
.diff
.f1
= diff_f1
;
2407 repo_write
.diff
.f2
= diff_f2
;
2408 repo_write
.diff
.fd1
= diff_fd1
;
2409 repo_write
.diff
.fd2
= diff_fd2
;
2411 STAILQ_INIT(&repo_write_client
.ref_updates
);
2413 err
= got_repo_open(&repo_write
.repo
, repo_path
, NULL
, pack_fds
);
2416 if (!got_repo_is_bare(repo_write
.repo
)) {
2417 err
= got_error_msg(GOT_ERR_NOT_GIT_REPO
,
2418 "bare git repository required");
2421 if (got_repo_get_object_format(repo_write
.repo
) != GOT_HASH_SHA1
) {
2422 err
= got_error_msg(GOT_ERR_NOT_IMPL
,
2423 "sha256 object IDs unsupported in network protocol");
2427 got_repo_temp_fds_set(repo_write
.repo
, temp_fds
);
2429 signal(SIGINT
, catch_sigint
);
2430 signal(SIGTERM
, catch_sigterm
);
2431 signal(SIGPIPE
, SIG_IGN
);
2432 signal(SIGHUP
, SIG_IGN
);
2434 if (imsgbuf_init(&iev
.ibuf
, GOTD_FILENO_MSG_PIPE
) == -1) {
2435 err
= got_error_from_errno("imsgbuf_init");
2438 imsgbuf_allow_fdpass(&iev
.ibuf
);
2439 iev
.handler
= repo_write_dispatch
;
2440 iev
.events
= EV_READ
;
2441 iev
.handler_arg
= NULL
;
2442 event_set(&iev
.ev
, iev
.ibuf
.fd
, EV_READ
, repo_write_dispatch
, &iev
);
2443 if (gotd_imsg_compose_event(&iev
, GOTD_IMSG_REPO_CHILD_READY
,
2444 PROC_REPO_WRITE
, -1, NULL
, 0) == -1) {
2445 err
= got_error_from_errno("imsg compose REPO_CHILD_READY");
2451 if (fclose(diff_f1
) == EOF
&& err
== NULL
)
2452 err
= got_error_from_errno("fclose");
2453 if (fclose(diff_f2
) == EOF
&& err
== NULL
)
2454 err
= got_error_from_errno("fclose");
2455 if (close(diff_fd1
) == -1 && err
== NULL
)
2456 err
= got_error_from_errno("close");
2457 if (close(diff_fd2
) == -1 && err
== NULL
)
2458 err
= got_error_from_errno("close");
2460 log_warnx("%s: %s", title
, err
->msg
);
2461 repo_write_shutdown();
2465 repo_write_shutdown(void)
2467 struct repo_write_client
*client
= &repo_write_client
;
2468 struct gotd_ref_update
*ref_update
;
2470 log_debug("%s: shutting down", repo_write
.title
);
2472 while (!STAILQ_EMPTY(&client
->ref_updates
)) {
2473 ref_update
= STAILQ_FIRST(&client
->ref_updates
);
2474 STAILQ_REMOVE_HEAD(&client
->ref_updates
, entry
);
2475 got_ref_close(ref_update
->ref
);
2479 got_pack_close(&client
->pack
);
2480 if (client
->fd
!= -1)
2482 if (client
->pack_pipe
!= -1)
2483 close(client
->pack_pipe
);
2484 if (client
->packidx_fd
!= -1)
2485 close(client
->packidx_fd
);
2487 if (repo_write
.repo
)
2488 got_repo_close(repo_write
.repo
);
2489 got_repo_pack_fds_close(repo_write
.pack_fds
);
2490 got_repo_temp_fds_close(repo_write
.temp_fds
);
2491 if (repo_write
.session_fd
!= -1)
2492 close(repo_write
.session_fd
);