2 * Copyright (c) 2019 Ori Bernstein <ori@openbsd.org>
3 * Copyright (c) 2021 Stefan Sperling <stsp@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <sys/types.h>
19 #include <sys/queue.h>
39 #include "got_error.h"
40 #include "got_object.h"
42 #include "got_version.h"
43 #include "got_fetch.h"
44 #include "got_reference.h"
46 #include "got_lib_sha1.h"
47 #include "got_lib_delta.h"
48 #include "got_lib_object.h"
49 #include "got_lib_object_parse.h"
50 #include "got_lib_privsep.h"
51 #include "got_lib_pack.h"
54 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
57 struct got_object *indexed;
60 static const struct got_error *
61 readn(ssize_t *off, int fd, void *buf, size_t n)
67 r = read(fd, buf + *off, n - *off);
69 return got_error_from_errno("read");
77 static const struct got_error *
83 fprintf(stderr, "%s: writepkt: 0000\n", getprogname());
85 w = write(fd, "0000", 4);
87 return got_error_from_errno("write");
89 return got_error(GOT_ERR_IO);
94 * Packet header contains a 4-byte hexstring which specifies the length
95 * of data which follows.
97 static const struct got_error *
98 read_pkthdr(int *datalen, int fd)
100 static const struct got_error *err = NULL;
109 err = readn(&r, fd, lenstr, 4);
113 /* implicit "0000" */
115 fprintf(stderr, "%s: readpkt: 0000\n", getprogname());
119 return got_error_msg(GOT_ERR_BAD_PACKET,
120 "wrong packet header length");
123 for (i = 0; i < 4; i++) {
124 if (!isprint((unsigned char)lenstr[i]))
125 return got_error_msg(GOT_ERR_BAD_PACKET,
126 "unprintable character in packet length field");
128 for (i = 0; i < 4; i++) {
129 if (!isxdigit((unsigned char)lenstr[i])) {
131 fprintf(stderr, "%s: bad length: '%s'\n",
132 getprogname(), lenstr);
133 return got_error_msg(GOT_ERR_BAD_PACKET,
134 "packet length not specified in hex");
138 len = strtol(lenstr, &e, 16);
139 if (lenstr[0] == '\0' || *e != '\0')
140 return got_error(GOT_ERR_BAD_PACKET);
141 if (errno == ERANGE && (len == LONG_MAX || len == LONG_MIN))
142 return got_error_msg(GOT_ERR_BAD_PACKET, "bad packet length");
143 if (len > INT_MAX || len < INT_MIN)
144 return got_error_msg(GOT_ERR_BAD_PACKET, "bad packet length");
149 return got_error_msg(GOT_ERR_BAD_PACKET, "packet too short");
156 static const struct got_error *
157 readpkt(int *outlen, int fd, char *buf, int buflen)
159 const struct got_error *err = NULL;
163 err = read_pkthdr(&datalen, fd);
167 if (datalen > buflen)
168 return got_error(GOT_ERR_NO_SPACE);
170 err = readn(&n, fd, buf, datalen);
174 return got_error_msg(GOT_ERR_BAD_PACKET, "short packet");
177 fprintf(stderr, "%s: readpkt: %zd:\t", getprogname(), n);
178 for (i = 0; i < n; i++) {
180 fputc(buf[i], stderr);
182 fprintf(stderr, "[0x%.2x]", buf[i]);
191 static const struct got_error *
192 writepkt(int fd, char *buf, int nbuf)
198 if (snprintf(len, sizeof(len), "%04x", nbuf + 4) >= sizeof(len))
199 return got_error(GOT_ERR_NO_SPACE);
200 w = write(fd, len, 4);
202 return got_error_from_errno("write");
204 return got_error(GOT_ERR_IO);
205 w = write(fd, buf, nbuf);
207 return got_error_from_errno("write");
209 return got_error(GOT_ERR_IO);
211 fprintf(stderr, "%s: writepkt: %s:\t", getprogname(), len);
212 for (i = 0; i < nbuf; i++) {
214 fputc(buf[i], stderr);
216 fprintf(stderr, "[0x%.2x]", buf[i]);
223 static const struct got_error *
224 tokenize_refline(char **tokens, char *line, int len, int maxtokens)
226 const struct got_error *err = NULL;
230 for (i = 0; i < maxtokens; i++)
233 for (i = 0; n < len && i < maxtokens; i++) {
234 while (isspace(*line)) {
239 while (*line != '\0' && n < len &&
240 (!isspace(*line) || i == maxtokens - 1)) {
244 tokens[i] = strndup(p, line - p);
245 if (tokens[i] == NULL) {
246 err = got_error_from_errno("strndup");
249 /* Skip \0 field-delimiter at end of token. */
250 while (line[0] == '\0' && n < len) {
256 err = got_error(GOT_ERR_NOT_REF);
260 for (j = 0; j < i; j++) {
268 static const struct got_error *
269 parse_refline(char **id_str, char **refname, char **server_capabilities,
272 const struct got_error *err = NULL;
275 err = tokenize_refline(tokens, line, len, nitems(tokens));
282 *refname = tokens[1];
285 *server_capabilities = tokens[2];
286 p = strrchr(*server_capabilities, '\n');
294 #define GOT_CAPA_AGENT "agent"
295 #define GOT_CAPA_OFS_DELTA "ofs-delta"
296 #define GOT_CAPA_SIDE_BAND_64K "side-band-64k"
297 #define GOT_CAPA_REPORT_STATUS "report-status"
298 #define GOT_CAPA_DELETE_REFS "delete-refs"
300 #define GOT_SIDEBAND_PACKFILE_DATA 1
301 #define GOT_SIDEBAND_PROGRESS_INFO 2
302 #define GOT_SIDEBAND_ERROR_INFO 3
305 struct got_capability {
309 static const struct got_capability got_capabilities[] = {
310 { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR },
311 { GOT_CAPA_OFS_DELTA, NULL },
313 { GOT_CAPA_SIDE_BAND_64K, NULL },
315 { GOT_CAPA_REPORT_STATUS, NULL },
316 { GOT_CAPA_DELETE_REFS, NULL },
319 static const struct got_error *
320 match_capability(char **my_capabilities, const char *capa,
321 const struct got_capability *mycapa)
326 equalsign = strchr(capa, '=');
328 if (strncmp(capa, mycapa->key, equalsign - capa) != 0)
331 if (strcmp(capa, mycapa->key) != 0)
335 if (asprintf(&s, "%s %s%s%s",
336 *my_capabilities != NULL ? *my_capabilities : "",
338 mycapa->value != NULL ? "=" : "",
339 mycapa->value != NULL? mycapa->value : "") == -1)
340 return got_error_from_errno("asprintf");
342 free(*my_capabilities);
343 *my_capabilities = s;
347 static const struct got_error *
348 match_capabilities(char **my_capabilities, char *server_capabilities)
350 const struct got_error *err = NULL;
354 *my_capabilities = NULL;
356 capa = strsep(&server_capabilities, " ");
357 for (i = 0; capa != NULL && i < nitems(got_capabilities); i++) {
358 err = match_capability(my_capabilities,
359 capa, &got_capabilities[i]);
365 if (*my_capabilities == NULL) {
366 *my_capabilities = strdup("");
367 if (*my_capabilities == NULL) {
368 err = got_error_from_errno("strdup");
374 * Workaround for github.
376 * Github will accept the pack but fail to update the references
377 * if we don't have capabilities advertised. Report-status seems
378 * harmless to add, so we add it.
380 * Github doesn't advertise any capabilities, so we can't check
381 * for compatibility. We just need to add it blindly.
383 if (strstr(*my_capabilities, GOT_CAPA_REPORT_STATUS) == NULL) {
385 if (asprintf(&s, "%s %s", *my_capabilities,
386 GOT_CAPA_REPORT_STATUS) == -1) {
387 err = got_error_from_errno("asprintf");
390 free(*my_capabilities);
391 *my_capabilities = s;
395 free(*my_capabilities);
396 *my_capabilities = NULL;
401 static const struct got_error *
402 send_upload_progress(struct imsgbuf *ibuf, off_t bytes)
404 if (imsg_compose(ibuf, GOT_IMSG_SEND_UPLOAD_PROGRESS, 0, 0, -1,
405 &bytes, sizeof(bytes)) == -1)
406 return got_error_from_errno(
407 "imsg_compose SEND_UPLOAD_PROGRESS");
409 return got_privsep_flush_imsg(ibuf);
412 static const struct got_error *
413 send_pack_request(struct imsgbuf *ibuf)
415 if (imsg_compose(ibuf, GOT_IMSG_SEND_PACK_REQUEST, 0, 0, -1,
417 return got_error_from_errno("imsg_compose SEND_PACK_REQUEST");
418 return got_privsep_flush_imsg(ibuf);
421 static const struct got_error *
422 send_done(struct imsgbuf *ibuf)
424 if (imsg_compose(ibuf, GOT_IMSG_SEND_DONE, 0, 0, -1, NULL, 0) == -1)
425 return got_error_from_errno("imsg_compose SEND_DONE");
426 return got_privsep_flush_imsg(ibuf);
429 static const struct got_error *
430 recv_packfd(int *packfd, struct imsgbuf *ibuf)
432 const struct got_error *err;
437 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
441 if (imsg.hdr.type == GOT_IMSG_STOP) {
442 err = got_error(GOT_ERR_CANCELLED);
446 if (imsg.hdr.type != GOT_IMSG_SEND_PACKFD) {
447 err = got_error(GOT_ERR_PRIVSEP_MSG);
451 if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) {
452 err = got_error(GOT_ERR_PRIVSEP_LEN);
462 static const struct got_error *
463 send_pack_file(int sendfd, int packfd, struct imsgbuf *ibuf)
465 const struct got_error *err;
466 unsigned char buf[8192];
470 if (lseek(packfd, 0L, SEEK_SET) == -1)
471 return got_error_from_errno("lseek");
474 r = read(packfd, buf, sizeof(buf));
476 return got_error_from_errno("read");
479 w = write(sendfd, buf, r);
481 return got_error_from_errno("write");
483 return got_error(GOT_ERR_IO);
485 err = send_upload_progress(ibuf, wtotal);
493 static const struct got_error *
494 send_error(const char *buf, size_t len)
496 static char msg[1024];
499 for (i = 0; i < len && i < sizeof(msg) - 1; i++) {
500 if (!isprint(buf[i]))
501 return got_error_msg(GOT_ERR_BAD_PACKET,
502 "non-printable error message received from server");
506 return got_error_msg(GOT_ERR_SEND_FAILED, msg);
509 static const struct got_error *
510 send_their_ref(struct imsgbuf *ibuf, struct got_object_id *refid,
513 const struct got_error *err = NULL;
515 size_t len, reflen = strlen(refname);
517 len = sizeof(struct got_imsg_send_remote_ref) + reflen;
518 if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE)
519 return got_error(GOT_ERR_NO_SPACE);
521 wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REMOTE_REF, 0, 0, len);
523 return got_error_from_errno("imsg_create SEND_REMOTE_REF");
525 /* Keep in sync with struct got_imsg_send_remote_ref definition! */
526 if (imsg_add(wbuf, refid->sha1, SHA1_DIGEST_LENGTH) == -1) {
527 err = got_error_from_errno("imsg_add SEND_REMOTE_REF");
531 if (imsg_add(wbuf, &reflen, sizeof(reflen)) == -1) {
532 err = got_error_from_errno("imsg_add SEND_REMOTE_REF");
536 if (imsg_add(wbuf, refname, reflen) == -1) {
537 err = got_error_from_errno("imsg_add SEND_REMOTE_REF");
543 imsg_close(ibuf, wbuf);
544 return got_privsep_flush_imsg(ibuf);
547 static const struct got_error *
548 send_ref_status(struct imsgbuf *ibuf, const char *refname, int success,
549 struct got_pathlist_head *refs, struct got_pathlist_head *delete_refs)
552 const struct got_error *err = NULL;
554 size_t len, reflen = strlen(refname);
555 struct got_pathlist_entry *pe;
559 eol = strchr(refname, '\n');
561 return got_error_msg(GOT_ERR_BAD_PACKET,
562 "unexpected message from server");
566 TAILQ_FOREACH(pe, refs, entry) {
567 if (strcmp(refname, pe->path) == 0) {
573 TAILQ_FOREACH(pe, delete_refs, entry) {
574 if (strcmp(refname, pe->path) == 0) {
581 return got_error_msg(GOT_ERR_BAD_PACKET,
582 "unexpected message from server");
585 len = sizeof(struct got_imsg_send_ref_status) + reflen;
586 if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE)
587 return got_error(GOT_ERR_NO_SPACE);
589 wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REF_STATUS,
592 return got_error_from_errno("imsg_create SEND_REF_STATUS");
594 /* Keep in sync with struct got_imsg_send_ref_status definition! */
595 if (imsg_add(wbuf, &success, sizeof(success)) == -1) {
596 err = got_error_from_errno("imsg_add SEND_REF_STATUS");
600 if (imsg_add(wbuf, &reflen, sizeof(reflen)) == -1) {
601 err = got_error_from_errno("imsg_add SEND_REF_STATUS");
605 if (imsg_add(wbuf, refname, reflen) == -1) {
606 err = got_error_from_errno("imsg_add SEND_REF_STATUS");
612 imsg_close(ibuf, wbuf);
613 return got_privsep_flush_imsg(ibuf);
616 static const struct got_error *
617 describe_refchange(int *n, int *sent_my_capabilites,
618 const char *my_capabilities, char *buf, size_t bufsize,
619 const char *refname, const char *old_hashstr, const char *new_hashstr)
621 *n = snprintf(buf, bufsize, "%s %s %s",
622 old_hashstr, new_hashstr, refname);
624 return got_error(GOT_ERR_NO_SPACE);
627 * We must announce our capabilities along with the first
628 * reference. Unfortunately, the protocol requires an embedded
629 * NUL as a separator between reference name and capabilities,
630 * which we have to deal with here.
631 * It also requires a linefeed for terminating packet data.
633 if (!*sent_my_capabilites && my_capabilities != NULL) {
635 if (*n >= bufsize - 1)
636 return got_error(GOT_ERR_NO_SPACE);
637 m = snprintf(buf + *n + 1, /* offset after '\0' */
638 bufsize - (*n + 1), "%s\n", my_capabilities);
639 if (*n + m >= bufsize)
640 return got_error(GOT_ERR_NO_SPACE);
642 *sent_my_capabilites = 1;
644 *n = strlcat(buf, "\n", bufsize);
646 return got_error(GOT_ERR_NO_SPACE);
652 static const struct got_error *
653 send_pack(int fd, struct got_pathlist_head *refs,
654 struct got_pathlist_head *delete_refs, struct imsgbuf *ibuf)
656 const struct got_error *err = NULL;
657 char buf[GOT_FETCH_PKTMAX];
658 unsigned char zero_id[SHA1_DIGEST_LENGTH] = { 0 };
659 char old_hashstr[SHA1_DIGEST_STRING_LENGTH];
660 char new_hashstr[SHA1_DIGEST_STRING_LENGTH];
661 struct got_pathlist_head their_refs;
665 char *id_str = NULL, *refname = NULL;
666 struct got_object_id *id = NULL;
667 char *server_capabilities = NULL, *my_capabilities = NULL;
668 struct got_pathlist_entry *pe;
669 int sent_my_capabilites = 0;
671 TAILQ_INIT(&their_refs);
673 if (TAILQ_EMPTY(refs) && TAILQ_EMPTY(delete_refs))
674 return got_error(GOT_ERR_SEND_EMPTY);
677 err = readpkt(&n, fd, buf, sizeof(buf));
682 if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) {
683 err = send_error(&buf[4], n - 4);
686 err = parse_refline(&id_str, &refname, &server_capabilities,
691 if (chattygot && server_capabilities[0] != '\0')
692 fprintf(stderr, "%s: server capabilities: %s\n",
693 getprogname(), server_capabilities);
694 err = match_capabilities(&my_capabilities,
695 server_capabilities);
699 fprintf(stderr, "%s: my capabilities:%s\n",
700 getprogname(), my_capabilities);
703 if (strstr(refname, "^{}")) {
705 fprintf(stderr, "%s: ignoring %s\n",
706 getprogname(), refname);
711 id = malloc(sizeof(*id));
713 err = got_error_from_errno("malloc");
716 if (!got_parse_sha1_digest(id->sha1, id_str)) {
717 err = got_error(GOT_ERR_BAD_OBJ_ID_STR);
720 err = send_their_ref(ibuf, id, refname);
724 err = got_pathlist_append(&their_refs, refname, id);
726 fprintf(stderr, "%s: remote has %s %s\n",
727 getprogname(), refname, id_str);
730 refname = NULL; /* do not free; owned by their_refs */
731 id = NULL; /* do not free; owned by their_refs */
734 if (!TAILQ_EMPTY(delete_refs)) {
735 if (my_capabilities == NULL ||
736 strstr(my_capabilities, GOT_CAPA_DELETE_REFS) == NULL) {
737 err = got_error(GOT_ERR_CAPA_DELETE_REFS);
742 TAILQ_FOREACH(pe, delete_refs, entry) {
743 const char *refname = pe->path;
744 struct got_pathlist_entry *their_pe;
745 struct got_object_id *their_id = NULL;
747 TAILQ_FOREACH(their_pe, &their_refs, entry) {
748 const char *their_refname = their_pe->path;
749 if (got_path_cmp(refname, their_refname,
750 strlen(refname), strlen(their_refname)) == 0) {
751 their_id = their_pe->data;
755 if (their_id == NULL) {
756 err = got_error_fmt(GOT_ERR_NOT_REF,
757 "%s does not exist in remote repository",
762 got_sha1_digest_to_str(their_id->sha1, old_hashstr,
763 sizeof(old_hashstr));
764 got_sha1_digest_to_str(zero_id, new_hashstr,
765 sizeof(new_hashstr));
766 err = describe_refchange(&n, &sent_my_capabilites,
767 my_capabilities, buf, sizeof(buf), refname,
768 old_hashstr, new_hashstr);
771 err = writepkt(fd, buf, n);
775 fprintf(stderr, "%s: deleting %s %s\n",
776 getprogname(), refname, old_hashstr);
781 TAILQ_FOREACH(pe, refs, entry) {
782 const char *refname = pe->path;
783 struct got_object_id *id = pe->data;
784 struct got_object_id *their_id = NULL;
785 struct got_pathlist_entry *their_pe;
787 TAILQ_FOREACH(their_pe, &their_refs, entry) {
788 const char *their_refname = their_pe->path;
789 if (got_path_cmp(refname, their_refname,
790 strlen(refname), strlen(their_refname)) == 0) {
791 their_id = their_pe->data;
796 if (got_object_id_cmp(id, their_id) == 0) {
799 "%s: no change for %s\n",
800 getprogname(), refname);
804 got_sha1_digest_to_str(their_id->sha1, old_hashstr,
805 sizeof(old_hashstr));
807 got_sha1_digest_to_str(zero_id, old_hashstr,
808 sizeof(old_hashstr));
810 got_sha1_digest_to_str(id->sha1, new_hashstr,
811 sizeof(new_hashstr));
812 err = describe_refchange(&n, &sent_my_capabilites,
813 my_capabilities, buf, sizeof(buf), refname,
814 old_hashstr, new_hashstr);
817 err = writepkt(fd, buf, n);
822 fprintf(stderr, "%s: updating %s %s -> %s\n",
823 getprogname(), refname, old_hashstr,
826 fprintf(stderr, "%s: creating %s %s\n",
827 getprogname(), refname, new_hashstr);
836 err = send_pack_request(ibuf);
840 err = recv_packfd(&packfd, ibuf);
844 err = send_pack_file(fd, packfd, ibuf);
848 err = readpkt(&n, fd, buf, sizeof(buf));
851 if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) {
852 err = send_error(&buf[4], n - 4);
854 } else if (n < 10 || strncmp(buf, "unpack ok\n", 10) != 0) {
855 err = got_error_msg(GOT_ERR_BAD_PACKET,
856 "unexpected message from server");
861 err = readpkt(&n, fd, buf, sizeof(buf));
865 err = got_error_msg(GOT_ERR_BAD_PACKET,
866 "unexpected message from server");
868 } else if (strncmp(buf, "ok ", 3) == 0) {
869 err = send_ref_status(ibuf, buf + 3, 1,
873 } else if (strncmp(buf, "ng ", 3) == 0) {
874 err = send_ref_status(ibuf, buf + 3, 0,
879 err = got_error_msg(GOT_ERR_BAD_PACKET,
880 "unexpected message from server");
886 err = send_done(ibuf);
888 TAILQ_FOREACH(pe, &their_refs, entry) {
889 free((void *)pe->path);
892 got_pathlist_free(&their_refs);
896 free(server_capabilities);
901 main(int argc, char **argv)
903 const struct got_error *err = NULL;
907 struct got_pathlist_head refs;
908 struct got_pathlist_head delete_refs;
909 struct got_pathlist_entry *pe;
910 struct got_imsg_send_request send_req;
911 struct got_imsg_send_ref href;
920 TAILQ_INIT(&delete_refs);
922 imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
924 /* revoke access to most system calls */
925 if (pledge("stdio recvfd", NULL) == -1) {
926 err = got_error_from_errno("pledge");
927 got_privsep_send_error(&ibuf, err);
931 if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
932 if (err->code == GOT_ERR_PRIVSEP_PIPE)
936 if (imsg.hdr.type == GOT_IMSG_STOP)
938 if (imsg.hdr.type != GOT_IMSG_SEND_REQUEST) {
939 err = got_error(GOT_ERR_PRIVSEP_MSG);
942 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
943 if (datalen < sizeof(send_req)) {
944 err = got_error(GOT_ERR_PRIVSEP_LEN);
947 memcpy(&send_req, imsg.data, sizeof(send_req));
951 if (send_req.verbosity > 0)
952 chattygot += send_req.verbosity;
954 for (i = 0; i < send_req.nrefs; i++) {
955 struct got_object_id *id;
958 if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
959 if (err->code == GOT_ERR_PRIVSEP_PIPE)
963 if (imsg.hdr.type == GOT_IMSG_STOP)
965 if (imsg.hdr.type != GOT_IMSG_SEND_REF) {
966 err = got_error(GOT_ERR_PRIVSEP_MSG);
969 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
970 if (datalen < sizeof(href)) {
971 err = got_error(GOT_ERR_PRIVSEP_LEN);
974 memcpy(&href, imsg.data, sizeof(href));
975 if (datalen - sizeof(href) < href.name_len) {
976 err = got_error(GOT_ERR_PRIVSEP_LEN);
979 refname = malloc(href.name_len + 1);
980 if (refname == NULL) {
981 err = got_error_from_errno("malloc");
984 memcpy(refname, imsg.data + sizeof(href), href.name_len);
985 refname[href.name_len] = '\0';
988 * Prevent sending of references that won't make any
989 * sense outside the local repository's context.
991 if (strncmp(refname, "refs/got/", 9) == 0 ||
992 strncmp(refname, "refs/remotes/", 13) == 0) {
993 err = got_error_fmt(GOT_ERR_SEND_BAD_REF,
998 id = malloc(sizeof(*id));
1001 err = got_error_from_errno("malloc");
1004 memcpy(id->sha1, href.id, SHA1_DIGEST_LENGTH);
1006 err = got_pathlist_append(&delete_refs, refname, id);
1008 err = got_pathlist_append(&refs, refname, id);
1018 err = send_pack(sendfd, &refs, &delete_refs, &ibuf);
1020 TAILQ_FOREACH(pe, &refs, entry) {
1021 free((char *)pe->path);
1024 got_pathlist_free(&refs);
1025 TAILQ_FOREACH(pe, &delete_refs, entry) {
1026 free((char *)pe->path);
1029 got_pathlist_free(&delete_refs);
1030 if (sendfd != -1 && close(sendfd) == -1 && err == NULL)
1031 err = got_error_from_errno("close");
1032 if (err != NULL && err->code != GOT_ERR_CANCELLED) {
1033 fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
1034 got_privsep_send_error(&ibuf, err);