Blob


1 /*
2 * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
3 *
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.
7 *
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.
15 */
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/uio.h>
20 #include <sys/socket.h>
21 #include <sys/wait.h>
22 #include <sys/mman.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdint.h>
29 #include <zlib.h>
30 #include <ctype.h>
31 #include <limits.h>
32 #include <time.h>
33 #include <unistd.h>
35 #include "got_compat.h"
37 #include "got_error.h"
38 #include "got_object.h"
39 #include "got_repository.h"
40 #include "got_opentemp.h"
41 #include "got_path.h"
43 #include "got_lib_sha1.h"
44 #include "got_lib_delta.h"
45 #include "got_lib_inflate.h"
46 #include "got_lib_object.h"
47 #include "got_lib_object_parse.h"
48 #include "got_lib_object_cache.h"
49 #include "got_lib_pack.h"
50 #include "got_lib_privsep.h"
51 #include "got_lib_repository.h"
53 #ifndef nitems
54 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
55 #endif
57 struct got_object_id *
58 got_object_id_dup(struct got_object_id *id1)
59 {
60 struct got_object_id *id2;
62 id2 = malloc(sizeof(*id2));
63 if (id2 == NULL)
64 return NULL;
65 memcpy(id2, id1, sizeof(*id2));
66 return id2;
67 }
69 int
70 got_object_id_cmp(const struct got_object_id *id1,
71 const struct got_object_id *id2)
72 {
73 return memcmp(id1->sha1, id2->sha1, SHA1_DIGEST_LENGTH);
74 }
76 const struct got_error *
77 got_object_qid_alloc_partial(struct got_object_qid **qid)
78 {
79 const struct got_error *err = NULL;
81 *qid = malloc(sizeof(**qid));
82 if (*qid == NULL)
83 return got_error_from_errno("malloc");
85 (*qid)->id = malloc(sizeof(*((*qid)->id)));
86 if ((*qid)->id == NULL) {
87 err = got_error_from_errno("malloc");
88 got_object_qid_free(*qid);
89 *qid = NULL;
90 return err;
91 }
92 (*qid)->data = NULL;
94 return NULL;
95 }
97 const struct got_error *
98 got_object_id_str(char **outbuf, struct got_object_id *id)
99 {
100 static const size_t len = SHA1_DIGEST_STRING_LENGTH;
102 *outbuf = malloc(len);
103 if (*outbuf == NULL)
104 return got_error_from_errno("malloc");
106 if (got_sha1_digest_to_str(id->sha1, *outbuf, len) == NULL) {
107 free(*outbuf);
108 *outbuf = NULL;
109 return got_error(GOT_ERR_BAD_OBJ_ID_STR);
112 return NULL;
115 void
116 got_object_close(struct got_object *obj)
118 if (obj->refcnt > 0) {
119 obj->refcnt--;
120 if (obj->refcnt > 0)
121 return;
124 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
125 struct got_delta *delta;
126 while (!STAILQ_EMPTY(&obj->deltas.entries)) {
127 delta = STAILQ_FIRST(&obj->deltas.entries);
128 STAILQ_REMOVE_HEAD(&obj->deltas.entries, entry);
129 free(delta);
132 free(obj);
135 const struct got_error *
136 got_object_raw_close(struct got_raw_object *obj)
138 const struct got_error *err = NULL;
140 if (obj->refcnt > 0) {
141 obj->refcnt--;
142 if (obj->refcnt > 0)
143 return NULL;
146 if (obj->f == NULL) {
147 if (obj->fd != -1) {
148 if (munmap(obj->data, obj->hdrlen + obj->size) == -1)
149 err = got_error_from_errno("munmap");
150 if (close(obj->fd) == -1 && err == NULL)
151 err = got_error_from_errno("close");
152 } else
153 free(obj->data);
154 } else {
155 if (fclose(obj->f) == EOF && err == NULL)
156 err = got_error_from_errno("fclose");
158 free(obj);
159 return err;
162 void
163 got_object_qid_free(struct got_object_qid *qid)
165 free(qid->id);
166 free(qid);
169 void
170 got_object_id_queue_free(struct got_object_id_queue *ids)
172 struct got_object_qid *qid;
174 while (!STAILQ_EMPTY(ids)) {
175 qid = STAILQ_FIRST(ids);
176 STAILQ_REMOVE_HEAD(ids, entry);
177 got_object_qid_free(qid);
181 const struct got_error *
182 got_object_parse_header(struct got_object **obj, char *buf, size_t len)
184 const char *obj_labels[] = {
185 GOT_OBJ_LABEL_COMMIT,
186 GOT_OBJ_LABEL_TREE,
187 GOT_OBJ_LABEL_BLOB,
188 GOT_OBJ_LABEL_TAG,
189 };
190 const int obj_types[] = {
191 GOT_OBJ_TYPE_COMMIT,
192 GOT_OBJ_TYPE_TREE,
193 GOT_OBJ_TYPE_BLOB,
194 GOT_OBJ_TYPE_TAG,
195 };
196 int type = 0;
197 size_t size = 0, hdrlen = 0;
198 size_t i;
200 *obj = NULL;
202 hdrlen = strnlen(buf, len) + 1 /* '\0' */;
203 if (hdrlen > len)
204 return got_error(GOT_ERR_BAD_OBJ_HDR);
206 for (i = 0; i < nitems(obj_labels); i++) {
207 const char *label = obj_labels[i];
208 size_t label_len = strlen(label);
209 const char *errstr;
211 if (strncmp(buf, label, label_len) != 0)
212 continue;
214 type = obj_types[i];
215 if (len <= label_len)
216 return got_error(GOT_ERR_BAD_OBJ_HDR);
217 size = strtonum(buf + label_len, 0, LONG_MAX, &errstr);
218 if (errstr != NULL)
219 return got_error(GOT_ERR_BAD_OBJ_HDR);
220 break;
223 if (type == 0)
224 return got_error(GOT_ERR_BAD_OBJ_HDR);
226 *obj = calloc(1, sizeof(**obj));
227 if (*obj == NULL)
228 return got_error_from_errno("calloc");
229 (*obj)->type = type;
230 (*obj)->hdrlen = hdrlen;
231 (*obj)->size = size;
232 return NULL;
235 const struct got_error *
236 got_object_read_header(struct got_object **obj, int fd)
238 const struct got_error *err;
239 struct got_inflate_buf zb;
240 uint8_t *buf;
241 const size_t zbsize = 64;
242 size_t outlen, totlen;
243 int nbuf = 1;
245 *obj = NULL;
247 buf = malloc(zbsize);
248 if (buf == NULL)
249 return got_error_from_errno("malloc");
251 err = got_inflate_init(&zb, buf, zbsize, NULL);
252 if (err)
253 return err;
255 totlen = 0;
256 do {
257 err = got_inflate_read_fd(&zb, fd, &outlen, NULL);
258 if (err)
259 goto done;
260 if (outlen == 0)
261 break;
262 totlen += outlen;
263 if (memchr(zb.outbuf, '\0', outlen) == NULL) {
264 uint8_t *newbuf;
265 nbuf++;
266 newbuf = recallocarray(buf, nbuf - 1, nbuf, zbsize);
267 if (newbuf == NULL) {
268 err = got_error_from_errno("recallocarray");
269 goto done;
271 buf = newbuf;
272 zb.outbuf = newbuf + totlen;
273 zb.outlen = (nbuf * zbsize) - totlen;
275 } while (memchr(zb.outbuf, '\0', outlen) == NULL);
277 err = got_object_parse_header(obj, buf, totlen);
278 done:
279 free(buf);
280 got_inflate_end(&zb);
281 return err;
284 struct got_commit_object *
285 got_object_commit_alloc_partial(void)
287 struct got_commit_object *commit;
289 commit = calloc(1, sizeof(*commit));
290 if (commit == NULL)
291 return NULL;
292 commit->tree_id = malloc(sizeof(*commit->tree_id));
293 if (commit->tree_id == NULL) {
294 free(commit);
295 return NULL;
298 STAILQ_INIT(&commit->parent_ids);
300 return commit;
303 const struct got_error *
304 got_object_commit_add_parent(struct got_commit_object *commit,
305 const char *id_str)
307 const struct got_error *err = NULL;
308 struct got_object_qid *qid;
310 err = got_object_qid_alloc_partial(&qid);
311 if (err)
312 return err;
314 if (!got_parse_sha1_digest(qid->id->sha1, id_str)) {
315 err = got_error(GOT_ERR_BAD_OBJ_DATA);
316 got_object_qid_free(qid);
317 return err;
320 STAILQ_INSERT_TAIL(&commit->parent_ids, qid, entry);
321 commit->nparents++;
323 return NULL;
326 static const struct got_error *
327 parse_gmtoff(time_t *gmtoff, const char *tzstr)
329 int sign = 1;
330 const char *p = tzstr;
331 time_t h, m;
333 *gmtoff = 0;
335 if (*p == '-')
336 sign = -1;
337 else if (*p != '+')
338 return got_error(GOT_ERR_BAD_OBJ_DATA);
339 p++;
340 if (!isdigit(*p) && !isdigit(*(p + 1)))
341 return got_error(GOT_ERR_BAD_OBJ_DATA);
342 h = (((*p - '0') * 10) + (*(p + 1) - '0'));
344 p += 2;
345 if (!isdigit(*p) && !isdigit(*(p + 1)))
346 return got_error(GOT_ERR_BAD_OBJ_DATA);
347 m = ((*p - '0') * 10) + (*(p + 1) - '0');
349 *gmtoff = (h * 60 * 60 + m * 60) * sign;
350 return NULL;
353 static const struct got_error *
354 parse_commit_time(time_t *time, time_t *gmtoff, char *committer)
356 const struct got_error *err = NULL;
357 const char *errstr;
358 char *space, *tzstr;
360 /* Parse and strip off trailing timezone indicator string. */
361 space = strrchr(committer, ' ');
362 if (space == NULL)
363 return got_error(GOT_ERR_BAD_OBJ_DATA);
364 tzstr = strdup(space + 1);
365 if (tzstr == NULL)
366 return got_error_from_errno("strdup");
367 err = parse_gmtoff(gmtoff, tzstr);
368 free(tzstr);
369 if (err) {
370 if (err->code != GOT_ERR_BAD_OBJ_DATA)
371 return err;
372 /* Old versions of Git omitted the timestamp. */
373 *time = 0;
374 *gmtoff = 0;
375 return NULL;
377 *space = '\0';
379 /* Timestamp is separated from committer name + email by space. */
380 space = strrchr(committer, ' ');
381 if (space == NULL)
382 return got_error(GOT_ERR_BAD_OBJ_DATA);
384 /* Timestamp parsed here is expressed as UNIX timestamp (UTC). */
385 *time = strtonum(space + 1, 0, INT64_MAX, &errstr);
386 if (errstr)
387 return got_error(GOT_ERR_BAD_OBJ_DATA);
389 /* Strip off parsed time information, leaving just author and email. */
390 *space = '\0';
392 return NULL;
395 void
396 got_object_commit_close(struct got_commit_object *commit)
398 if (commit->refcnt > 0) {
399 commit->refcnt--;
400 if (commit->refcnt > 0)
401 return;
404 got_object_id_queue_free(&commit->parent_ids);
405 free(commit->tree_id);
406 free(commit->author);
407 free(commit->committer);
408 free(commit->logmsg);
409 free(commit);
412 struct got_object_id *
413 got_object_commit_get_tree_id(struct got_commit_object *commit)
415 return commit->tree_id;
418 int
419 got_object_commit_get_nparents(struct got_commit_object *commit)
421 return commit->nparents;
424 const struct got_object_id_queue *
425 got_object_commit_get_parent_ids(struct got_commit_object *commit)
427 return &commit->parent_ids;
430 const char *
431 got_object_commit_get_author(struct got_commit_object *commit)
433 return commit->author;
436 time_t
437 got_object_commit_get_author_time(struct got_commit_object *commit)
439 return commit->author_time;
442 time_t got_object_commit_get_author_gmtoff(struct got_commit_object *commit)
444 return commit->author_gmtoff;
447 const char *
448 got_object_commit_get_committer(struct got_commit_object *commit)
450 return commit->committer;
453 time_t
454 got_object_commit_get_committer_time(struct got_commit_object *commit)
456 return commit->committer_time;
459 time_t
460 got_object_commit_get_committer_gmtoff(struct got_commit_object *commit)
462 return commit->committer_gmtoff;
465 const struct got_error *
466 got_object_commit_get_logmsg(char **logmsg, struct got_commit_object *commit)
468 const struct got_error *err = NULL;
469 const char *src;
470 char *dst;
471 size_t len;
473 len = strlen(commit->logmsg);
474 *logmsg = malloc(len + 2); /* leave room for a trailing \n and \0 */
475 if (*logmsg == NULL)
476 return got_error_from_errno("malloc");
478 /*
479 * Strip out unusual headers. Headers are separated from the commit
480 * message body by a single empty line.
481 */
482 src = commit->logmsg;
483 dst = *logmsg;
484 while (*src != '\0' && *src != '\n') {
485 int copy_header = 1, eol = 0;
486 if (strncmp(src, GOT_COMMIT_LABEL_TREE,
487 strlen(GOT_COMMIT_LABEL_TREE)) != 0 &&
488 strncmp(src, GOT_COMMIT_LABEL_AUTHOR,
489 strlen(GOT_COMMIT_LABEL_AUTHOR)) != 0 &&
490 strncmp(src, GOT_COMMIT_LABEL_PARENT,
491 strlen(GOT_COMMIT_LABEL_PARENT)) != 0 &&
492 strncmp(src, GOT_COMMIT_LABEL_COMMITTER,
493 strlen(GOT_COMMIT_LABEL_COMMITTER)) != 0)
494 copy_header = 0;
496 while (*src != '\0' && !eol) {
497 if (copy_header) {
498 *dst = *src;
499 dst++;
501 if (*src == '\n')
502 eol = 1;
503 src++;
506 *dst = '\0';
508 if (strlcat(*logmsg, src, len + 1) >= len + 1) {
509 err = got_error(GOT_ERR_NO_SPACE);
510 goto done;
513 /* Trim redundant trailing whitespace. */
514 len = strlen(*logmsg);
515 while (len > 1 && isspace((unsigned char)(*logmsg)[len - 2]) &&
516 isspace((unsigned char)(*logmsg)[len - 1])) {
517 (*logmsg)[len - 1] = '\0';
518 len--;
521 /* Append a trailing newline if missing. */
522 if (len > 0 && (*logmsg)[len - 1] != '\n') {
523 (*logmsg)[len] = '\n';
524 (*logmsg)[len + 1] = '\0';
526 done:
527 if (err) {
528 free(*logmsg);
529 *logmsg = NULL;
531 return err;
534 const char *
535 got_object_commit_get_logmsg_raw(struct got_commit_object *commit)
537 return commit->logmsg;
540 const struct got_error *
541 got_object_parse_commit(struct got_commit_object **commit, char *buf,
542 size_t len)
544 const struct got_error *err = NULL;
545 char *s = buf;
546 size_t label_len;
547 ssize_t remain = (ssize_t)len;
549 if (remain == 0)
550 return got_error(GOT_ERR_BAD_OBJ_DATA);
552 *commit = got_object_commit_alloc_partial();
553 if (*commit == NULL)
554 return got_error_from_errno("got_object_commit_alloc_partial");
556 label_len = strlen(GOT_COMMIT_LABEL_TREE);
557 if (strncmp(s, GOT_COMMIT_LABEL_TREE, label_len) == 0) {
558 remain -= label_len;
559 if (remain < SHA1_DIGEST_STRING_LENGTH) {
560 err = got_error(GOT_ERR_BAD_OBJ_DATA);
561 goto done;
563 s += label_len;
564 if (!got_parse_sha1_digest((*commit)->tree_id->sha1, s)) {
565 err = got_error(GOT_ERR_BAD_OBJ_DATA);
566 goto done;
568 remain -= SHA1_DIGEST_STRING_LENGTH;
569 s += SHA1_DIGEST_STRING_LENGTH;
570 } else {
571 err = got_error(GOT_ERR_BAD_OBJ_DATA);
572 goto done;
575 label_len = strlen(GOT_COMMIT_LABEL_PARENT);
576 while (strncmp(s, GOT_COMMIT_LABEL_PARENT, label_len) == 0) {
577 remain -= label_len;
578 if (remain < SHA1_DIGEST_STRING_LENGTH) {
579 err = got_error(GOT_ERR_BAD_OBJ_DATA);
580 goto done;
582 s += label_len;
583 err = got_object_commit_add_parent(*commit, s);
584 if (err)
585 goto done;
587 remain -= SHA1_DIGEST_STRING_LENGTH;
588 s += SHA1_DIGEST_STRING_LENGTH;
591 label_len = strlen(GOT_COMMIT_LABEL_AUTHOR);
592 if (strncmp(s, GOT_COMMIT_LABEL_AUTHOR, label_len) == 0) {
593 char *p;
594 size_t slen;
596 remain -= label_len;
597 if (remain <= 0) {
598 err = got_error(GOT_ERR_BAD_OBJ_DATA);
599 goto done;
601 s += label_len;
602 p = memchr(s, '\n', remain);
603 if (p == NULL) {
604 err = got_error(GOT_ERR_BAD_OBJ_DATA);
605 goto done;
607 *p = '\0';
608 slen = strlen(s);
609 err = parse_commit_time(&(*commit)->author_time,
610 &(*commit)->author_gmtoff, s);
611 if (err)
612 goto done;
613 (*commit)->author = strdup(s);
614 if ((*commit)->author == NULL) {
615 err = got_error_from_errno("strdup");
616 goto done;
618 s += slen + 1;
619 remain -= slen + 1;
622 label_len = strlen(GOT_COMMIT_LABEL_COMMITTER);
623 if (strncmp(s, GOT_COMMIT_LABEL_COMMITTER, label_len) == 0) {
624 char *p;
625 size_t slen;
627 remain -= label_len;
628 if (remain <= 0) {
629 err = got_error(GOT_ERR_BAD_OBJ_DATA);
630 goto done;
632 s += label_len;
633 p = memchr(s, '\n', remain);
634 if (p == NULL) {
635 err = got_error(GOT_ERR_BAD_OBJ_DATA);
636 goto done;
638 *p = '\0';
639 slen = strlen(s);
640 err = parse_commit_time(&(*commit)->committer_time,
641 &(*commit)->committer_gmtoff, s);
642 if (err)
643 goto done;
644 (*commit)->committer = strdup(s);
645 if ((*commit)->committer == NULL) {
646 err = got_error_from_errno("strdup");
647 goto done;
649 s += slen + 1;
650 remain -= slen + 1;
653 (*commit)->logmsg = strndup(s, remain);
654 if ((*commit)->logmsg == NULL) {
655 err = got_error_from_errno("strndup");
656 goto done;
658 done:
659 if (err) {
660 got_object_commit_close(*commit);
661 *commit = NULL;
663 return err;
666 void
667 got_object_tree_close(struct got_tree_object *tree)
669 if (tree->refcnt > 0) {
670 tree->refcnt--;
671 if (tree->refcnt > 0)
672 return;
675 free(tree->entries);
676 free(tree);
679 static const struct got_error *
680 parse_tree_entry(struct got_parsed_tree_entry **pte, const char **name,
681 size_t *elen, char *buf,
682 size_t maxlen)
684 char *p, *space;
685 const struct got_error *err = NULL;
687 *name = NULL;
688 *elen = 0;
690 *pte = malloc(sizeof(**pte));
691 if (*pte == NULL)
692 return got_error_from_errno("malloc");
694 *elen = strnlen(buf, maxlen) + 1;
695 if (*elen > maxlen) {
696 free(*pte);
697 *pte = NULL;
698 return got_error(GOT_ERR_BAD_OBJ_DATA);
701 space = memchr(buf, ' ', *elen);
702 if (space == NULL || space <= buf) {
703 err = got_error(GOT_ERR_BAD_OBJ_DATA);
704 free(*pte);
705 *pte = NULL;
706 return err;
708 (*pte)->mode = 0;
709 p = buf;
710 while (p < space) {
711 if (*p < '0' && *p > '7') {
712 err = got_error(GOT_ERR_BAD_OBJ_DATA);
713 goto done;
715 (*pte)->mode <<= 3;
716 (*pte)->mode |= *p - '0';
717 p++;
720 if (*elen > maxlen || maxlen - *elen < SHA1_DIGEST_LENGTH) {
721 err = got_error(GOT_ERR_BAD_OBJ_DATA);
722 goto done;
724 *name = space + 1;
725 buf += *elen;
726 (*pte)->id = buf;
727 *elen += SHA1_DIGEST_LENGTH;
728 done:
729 if (err) {
730 free(*pte);
731 *pte = NULL;
733 return err;
736 const struct got_error *
737 got_object_parse_tree(struct got_pathlist_head *entries, int *nentries,
738 uint8_t *buf, size_t len)
740 const struct got_error *err = NULL;
741 size_t remain = len;
743 *nentries = 0;
744 if (remain == 0)
745 return NULL; /* tree is empty */
747 while (remain > 0) {
748 struct got_parsed_tree_entry *pte;
749 struct got_pathlist_entry *new = NULL;
750 const char *name;
751 size_t elen;
753 err = parse_tree_entry(&pte, &name, &elen, buf, remain);
754 if (err)
755 goto done;
756 err = got_pathlist_insert(&new, entries, name, pte);
757 if (err)
758 goto done;
759 if (new == NULL) {
760 err = got_error(GOT_ERR_TREE_DUP_ENTRY);
761 goto done;
763 buf += elen;
764 remain -= elen;
765 (*nentries)++;
768 if (remain != 0) {
769 err = got_error(GOT_ERR_BAD_OBJ_DATA);
770 goto done;
772 done:
773 if (err) {
774 got_object_parsed_tree_entries_free(entries);
775 *nentries = 0;
777 return err;
780 void
781 got_object_parsed_tree_entries_free(struct got_pathlist_head *entries)
783 struct got_pathlist_entry *pe;
785 TAILQ_FOREACH(pe, entries, entry) {
786 struct got_parsed_tree_entry *pte = pe->data;
787 free(pte);
789 got_pathlist_free(entries);
792 void
793 got_object_tag_close(struct got_tag_object *tag)
795 if (tag->refcnt > 0) {
796 tag->refcnt--;
797 if (tag->refcnt > 0)
798 return;
801 free(tag->tag);
802 free(tag->tagger);
803 free(tag->tagmsg);
804 free(tag);
807 const struct got_error *
808 got_object_parse_tag(struct got_tag_object **tag, uint8_t *buf, size_t len)
810 const struct got_error *err = NULL;
811 size_t remain = len;
812 char *s = buf;
813 size_t label_len;
815 if (remain == 0)
816 return got_error(GOT_ERR_BAD_OBJ_DATA);
818 *tag = calloc(1, sizeof(**tag));
819 if (*tag == NULL)
820 return got_error_from_errno("calloc");
822 label_len = strlen(GOT_TAG_LABEL_OBJECT);
823 if (strncmp(s, GOT_TAG_LABEL_OBJECT, label_len) == 0) {
824 remain -= label_len;
825 if (remain < SHA1_DIGEST_STRING_LENGTH) {
826 err = got_error(GOT_ERR_BAD_OBJ_DATA);
827 goto done;
829 s += label_len;
830 if (!got_parse_sha1_digest((*tag)->id.sha1, s)) {
831 err = got_error(GOT_ERR_BAD_OBJ_DATA);
832 goto done;
834 remain -= SHA1_DIGEST_STRING_LENGTH;
835 s += SHA1_DIGEST_STRING_LENGTH;
836 } else {
837 err = got_error(GOT_ERR_BAD_OBJ_DATA);
838 goto done;
841 if (remain <= 0) {
842 err = got_error(GOT_ERR_BAD_OBJ_DATA);
843 goto done;
846 label_len = strlen(GOT_TAG_LABEL_TYPE);
847 if (strncmp(s, GOT_TAG_LABEL_TYPE, label_len) == 0) {
848 remain -= label_len;
849 if (remain <= 0) {
850 err = got_error(GOT_ERR_BAD_OBJ_DATA);
851 goto done;
853 s += label_len;
854 if (strncmp(s, GOT_OBJ_LABEL_COMMIT,
855 strlen(GOT_OBJ_LABEL_COMMIT)) == 0) {
856 (*tag)->obj_type = GOT_OBJ_TYPE_COMMIT;
857 label_len = strlen(GOT_OBJ_LABEL_COMMIT);
858 s += label_len;
859 remain -= label_len;
860 } else if (strncmp(s, GOT_OBJ_LABEL_TREE,
861 strlen(GOT_OBJ_LABEL_TREE)) == 0) {
862 (*tag)->obj_type = GOT_OBJ_TYPE_TREE;
863 label_len = strlen(GOT_OBJ_LABEL_TREE);
864 s += label_len;
865 remain -= label_len;
866 } else if (strncmp(s, GOT_OBJ_LABEL_BLOB,
867 strlen(GOT_OBJ_LABEL_BLOB)) == 0) {
868 (*tag)->obj_type = GOT_OBJ_TYPE_BLOB;
869 label_len = strlen(GOT_OBJ_LABEL_BLOB);
870 s += label_len;
871 remain -= label_len;
872 } else if (strncmp(s, GOT_OBJ_LABEL_TAG,
873 strlen(GOT_OBJ_LABEL_TAG)) == 0) {
874 (*tag)->obj_type = GOT_OBJ_TYPE_TAG;
875 label_len = strlen(GOT_OBJ_LABEL_TAG);
876 s += label_len;
877 remain -= label_len;
878 } else {
879 err = got_error(GOT_ERR_BAD_OBJ_DATA);
880 goto done;
883 if (remain <= 0 || *s != '\n') {
884 err = got_error(GOT_ERR_BAD_OBJ_DATA);
885 goto done;
887 s++;
888 remain--;
889 if (remain <= 0) {
890 err = got_error(GOT_ERR_BAD_OBJ_DATA);
891 goto done;
893 } else {
894 err = got_error(GOT_ERR_BAD_OBJ_DATA);
895 goto done;
898 label_len = strlen(GOT_TAG_LABEL_TAG);
899 if (strncmp(s, GOT_TAG_LABEL_TAG, label_len) == 0) {
900 char *p;
901 size_t slen;
902 remain -= label_len;
903 if (remain <= 0) {
904 err = got_error(GOT_ERR_BAD_OBJ_DATA);
905 goto done;
907 s += label_len;
908 p = memchr(s, '\n', remain);
909 if (p == NULL) {
910 err = got_error(GOT_ERR_BAD_OBJ_DATA);
911 goto done;
913 *p = '\0';
914 slen = strlen(s);
915 (*tag)->tag = strndup(s, slen);
916 if ((*tag)->tag == NULL) {
917 err = got_error_from_errno("strndup");
918 goto done;
920 s += slen + 1;
921 remain -= slen + 1;
922 if (remain <= 0) {
923 err = got_error(GOT_ERR_BAD_OBJ_DATA);
924 goto done;
926 } else {
927 err = got_error(GOT_ERR_BAD_OBJ_DATA);
928 goto done;
931 label_len = strlen(GOT_TAG_LABEL_TAGGER);
932 if (strncmp(s, GOT_TAG_LABEL_TAGGER, label_len) == 0) {
933 char *p;
934 size_t slen;
936 remain -= label_len;
937 if (remain <= 0) {
938 err = got_error(GOT_ERR_BAD_OBJ_DATA);
939 goto done;
941 s += label_len;
942 p = memchr(s, '\n', remain);
943 if (p == NULL) {
944 err = got_error(GOT_ERR_BAD_OBJ_DATA);
945 goto done;
947 *p = '\0';
948 slen = strlen(s);
949 err = parse_commit_time(&(*tag)->tagger_time,
950 &(*tag)->tagger_gmtoff, s);
951 if (err)
952 goto done;
953 (*tag)->tagger = strdup(s);
954 if ((*tag)->tagger == NULL) {
955 err = got_error_from_errno("strdup");
956 goto done;
958 s += slen + 1;
959 remain -= slen + 1;
960 if (remain < 0) {
961 err = got_error(GOT_ERR_BAD_OBJ_DATA);
962 goto done;
964 } else {
965 /* Some old tags in the Linux git repo have no tagger. */
966 (*tag)->tagger = strdup("");
967 if ((*tag)->tagger == NULL) {
968 err = got_error_from_errno("strdup");
969 goto done;
973 (*tag)->tagmsg = strndup(s, remain);
974 if ((*tag)->tagmsg == NULL) {
975 err = got_error_from_errno("strndup");
976 goto done;
978 done:
979 if (err) {
980 got_object_tag_close(*tag);
981 *tag = NULL;
983 return err;
986 const struct got_error *
987 got_read_file_to_mem(uint8_t **outbuf, size_t *outlen, FILE *f)
989 const struct got_error *err = NULL;
990 static const size_t blocksize = 512;
991 size_t n, total, remain;
992 uint8_t *buf;
994 *outbuf = NULL;
995 *outlen = 0;
997 buf = malloc(blocksize);
998 if (buf == NULL)
999 return got_error_from_errno("malloc");
1001 remain = blocksize;
1002 total = 0;
1003 for (;;) {
1004 if (remain == 0) {
1005 uint8_t *newbuf;
1006 newbuf = reallocarray(buf, 1, total + blocksize);
1007 if (newbuf == NULL) {
1008 err = got_error_from_errno("reallocarray");
1009 goto done;
1011 buf = newbuf;
1012 remain += blocksize;
1014 n = fread(buf + total, 1, remain, f);
1015 if (n == 0) {
1016 if (ferror(f)) {
1017 err = got_ferror(f, GOT_ERR_IO);
1018 goto done;
1020 break; /* EOF */
1022 remain -= n;
1023 total += n;
1026 done:
1027 if (err == NULL) {
1028 *outbuf = buf;
1029 *outlen = total;
1030 } else
1031 free(buf);
1032 return err;