2 * Copyright (c) 2018, 2019, 2020 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/types.h>
21 #include <sys/queue.h>
23 #include <sys/socket.h>
38 #include "got_error.h"
39 #include "got_object.h"
40 #include "got_repository.h"
41 #include "got_opentemp.h"
44 #include "got_lib_hash.h"
45 #include "got_lib_delta.h"
46 #include "got_lib_inflate.h"
47 #include "got_lib_object.h"
48 #include "got_lib_object_parse.h"
49 #include "got_lib_object_qid.h"
50 #include "got_lib_object_cache.h"
51 #include "got_lib_pack.h"
52 #include "got_lib_repository.h"
55 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
58 const struct got_error
*
59 got_object_type_label(const char **label
, int obj_type
)
61 const struct got_error
*err
= NULL
;
64 case GOT_OBJ_TYPE_BLOB
:
65 *label
= GOT_OBJ_LABEL_BLOB
;
67 case GOT_OBJ_TYPE_TREE
:
68 *label
= GOT_OBJ_LABEL_TREE
;
70 case GOT_OBJ_TYPE_COMMIT
:
71 *label
= GOT_OBJ_LABEL_COMMIT
;
73 case GOT_OBJ_TYPE_TAG
:
74 *label
= GOT_OBJ_LABEL_TAG
;
78 err
= got_error(GOT_ERR_OBJ_TYPE
);
86 got_object_close(struct got_object
*obj
)
88 if (obj
->refcnt
> 0) {
94 if (obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) {
95 struct got_delta
*delta
;
96 while (!STAILQ_EMPTY(&obj
->deltas
.entries
)) {
97 delta
= STAILQ_FIRST(&obj
->deltas
.entries
);
98 STAILQ_REMOVE_HEAD(&obj
->deltas
.entries
, entry
);
105 const struct got_error
*
106 got_object_raw_close(struct got_raw_object
*obj
)
108 const struct got_error
*err
= NULL
;
110 if (obj
->refcnt
> 0) {
119 if (obj
->f
== NULL
) {
121 if (munmap(obj
->data
, obj
->hdrlen
+ obj
->size
) == -1)
122 err
= got_error_from_errno("munmap");
123 if (close(obj
->fd
) == -1 && err
== NULL
)
124 err
= got_error_from_errno("close");
128 if (fclose(obj
->f
) == EOF
&& err
== NULL
)
129 err
= got_error_from_errno("fclose");
135 const struct got_error
*
136 got_object_parse_header(struct got_object
**obj
, char *buf
, size_t len
)
138 const char *obj_labels
[] = {
139 GOT_OBJ_LABEL_COMMIT
,
144 const int obj_types
[] = {
157 end
= memchr(buf
, '\0', len
);
159 return got_error(GOT_ERR_BAD_OBJ_HDR
);
161 for (i
= 0; i
< nitems(obj_labels
); i
++) {
162 const char *label
= obj_labels
[i
];
163 size_t label_len
= strlen(label
);
166 if (len
<= label_len
|| buf
+ label_len
>= end
||
167 strncmp(buf
, label
, label_len
) != 0)
171 size
= strtonum(buf
+ label_len
, 0, LONG_MAX
, &errstr
);
173 return got_error(GOT_ERR_BAD_OBJ_HDR
);
178 return got_error(GOT_ERR_BAD_OBJ_HDR
);
180 *obj
= calloc(1, sizeof(**obj
));
182 return got_error_from_errno("calloc");
184 (*obj
)->hdrlen
= end
- buf
+ 1;
189 const struct got_error
*
190 got_object_read_header(struct got_object
**obj
, int fd
)
192 const struct got_error
*err
;
193 struct got_inflate_buf zb
;
195 const size_t zbsize
= 64;
196 size_t outlen
, totlen
;
201 buf
= malloc(zbsize
);
203 return got_error_from_errno("malloc");
206 err
= got_inflate_init(&zb
, buf
, zbsize
, NULL
);
212 err
= got_inflate_read_fd(&zb
, fd
, &outlen
, NULL
);
218 if (memchr(zb
.outbuf
, '\0', outlen
) == NULL
) {
221 newbuf
= recallocarray(buf
, nbuf
- 1, nbuf
, zbsize
);
222 if (newbuf
== NULL
) {
223 err
= got_error_from_errno("recallocarray");
227 zb
.outbuf
= newbuf
+ totlen
;
228 zb
.outlen
= (nbuf
* zbsize
) - totlen
;
230 } while (memchr(zb
.outbuf
, '\0', outlen
) == NULL
);
232 err
= got_object_parse_header(obj
, buf
, totlen
);
235 got_inflate_end(&zb
);
239 const struct got_error
*
240 got_object_read_raw(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
241 size_t max_in_mem_size
, int outfd
, struct got_object_id
*expected_id
,
244 const struct got_error
*err
= NULL
;
245 struct got_object
*obj
;
246 struct got_inflate_checksum csum
;
247 struct got_object_id id
;
249 size_t len
, consumed
;
256 got_hash_init(&ctx
, expected_id
->algo
);
257 memset(&csum
, 0, sizeof(csum
));
258 csum
.output_ctx
= &ctx
;
260 if (lseek(infd
, SEEK_SET
, 0) == -1)
261 return got_error_from_errno("lseek");
263 err
= got_object_read_header(&obj
, infd
);
267 if (lseek(infd
, SEEK_SET
, 0) == -1)
268 return got_error_from_errno("lseek");
270 if (obj
->size
+ obj
->hdrlen
<= max_in_mem_size
) {
271 err
= got_inflate_to_mem_fd(outbuf
, &len
, &consumed
, &csum
,
272 obj
->size
+ obj
->hdrlen
, infd
);
276 * XXX This uses an extra file descriptor for no good reason.
277 * We should have got_inflate_fd_to_fd().
281 return got_error_from_errno("dup");
284 err
= got_error_from_errno("fdopen");
288 err
= got_inflate_to_fd(&len
, f
, &csum
, outfd
);
293 if (len
< obj
->hdrlen
|| len
!= obj
->hdrlen
+ obj
->size
) {
294 err
= got_error(GOT_ERR_BAD_OBJ_HDR
);
298 got_hash_final_object_id(&ctx
, &id
);
299 if (got_object_id_cmp(expected_id
, &id
) != 0) {
300 err
= got_error_checksum(expected_id
);
305 *hdrlen
= obj
->hdrlen
;
307 got_object_close(obj
);
308 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
309 err
= got_error_from_errno("fclose");
313 struct got_commit_object
*
314 got_object_commit_alloc_partial(void)
316 struct got_commit_object
*commit
;
318 commit
= calloc(1, sizeof(*commit
));
321 commit
->tree_id
= malloc(sizeof(*commit
->tree_id
));
322 if (commit
->tree_id
== NULL
) {
327 STAILQ_INIT(&commit
->parent_ids
);
332 const struct got_error
*
333 got_object_commit_add_parent(struct got_commit_object
*commit
,
334 const char *id_str
, enum got_hash_algorithm algo
)
336 const struct got_error
*err
= NULL
;
337 struct got_object_qid
*qid
;
339 err
= got_object_qid_alloc_partial(&qid
);
343 if (!got_parse_object_id(&qid
->id
, id_str
, algo
)) {
344 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
345 got_object_qid_free(qid
);
349 STAILQ_INSERT_TAIL(&commit
->parent_ids
, qid
, entry
);
355 static const struct got_error
*
356 parse_gmtoff(time_t *gmtoff
, const char *tzstr
)
359 const char *p
= tzstr
;
367 return got_error(GOT_ERR_BAD_OBJ_DATA
);
369 if (!isdigit((unsigned char)*p
) &&
370 !isdigit((unsigned char)*(p
+ 1)))
371 return got_error(GOT_ERR_BAD_OBJ_DATA
);
372 h
= (((*p
- '0') * 10) + (*(p
+ 1) - '0'));
375 if (!isdigit((unsigned char)*p
) &&
376 !isdigit((unsigned char)*(p
+ 1)))
377 return got_error(GOT_ERR_BAD_OBJ_DATA
);
378 m
= ((*p
- '0') * 10) + (*(p
+ 1) - '0');
380 *gmtoff
= (h
* 60 * 60 + m
* 60) * sign
;
384 static const struct got_error
*
385 parse_commit_time(time_t *time
, time_t *gmtoff
, char *committer
)
387 const struct got_error
*err
= NULL
;
391 /* Parse and strip off trailing timezone indicator string. */
392 space
= strrchr(committer
, ' ');
394 return got_error(GOT_ERR_BAD_OBJ_DATA
);
395 tzstr
= strdup(space
+ 1);
397 return got_error_from_errno("strdup");
398 err
= parse_gmtoff(gmtoff
, tzstr
);
401 if (err
->code
!= GOT_ERR_BAD_OBJ_DATA
)
403 /* Old versions of Git omitted the timestamp. */
410 /* Timestamp is separated from committer name + email by space. */
411 space
= strrchr(committer
, ' ');
413 return got_error(GOT_ERR_BAD_OBJ_DATA
);
415 /* Timestamp parsed here is expressed as UNIX timestamp (UTC). */
416 *time
= strtonum(space
+ 1, 0, INT64_MAX
, &errstr
);
418 return got_error(GOT_ERR_BAD_OBJ_DATA
);
420 /* Strip off parsed time information, leaving just author and email. */
427 got_object_commit_close(struct got_commit_object
*commit
)
429 if (commit
->refcnt
> 0) {
431 if (commit
->refcnt
> 0)
435 got_object_id_queue_free(&commit
->parent_ids
);
436 free(commit
->tree_id
);
437 free(commit
->author
);
438 free(commit
->committer
);
439 free(commit
->logmsg
);
443 struct got_object_id
*
444 got_object_commit_get_tree_id(struct got_commit_object
*commit
)
446 return commit
->tree_id
;
450 got_object_commit_get_nparents(struct got_commit_object
*commit
)
452 return commit
->nparents
;
455 const struct got_object_id_queue
*
456 got_object_commit_get_parent_ids(struct got_commit_object
*commit
)
458 return &commit
->parent_ids
;
462 got_object_commit_get_author(struct got_commit_object
*commit
)
464 return commit
->author
;
468 got_object_commit_get_author_time(struct got_commit_object
*commit
)
470 return commit
->author_time
;
473 time_t got_object_commit_get_author_gmtoff(struct got_commit_object
*commit
)
475 return commit
->author_gmtoff
;
479 got_object_commit_get_committer(struct got_commit_object
*commit
)
481 return commit
->committer
;
485 got_object_commit_get_committer_time(struct got_commit_object
*commit
)
487 return commit
->committer_time
;
491 got_object_commit_get_committer_gmtoff(struct got_commit_object
*commit
)
493 return commit
->committer_gmtoff
;
496 const struct got_error
*
497 got_object_commit_get_logmsg(char **logmsg
, struct got_commit_object
*commit
)
499 const struct got_error
*err
= NULL
;
504 len
= strlen(commit
->logmsg
);
505 *logmsg
= malloc(len
+ 2); /* leave room for a trailing \n and \0 */
507 return got_error_from_errno("malloc");
510 * Strip out unusual headers. Headers are separated from the commit
511 * message body by a single empty line.
513 src
= commit
->logmsg
;
515 while (*src
!= '\0' && *src
!= '\n') {
516 int copy_header
= 1, eol
= 0;
517 if (strncmp(src
, GOT_COMMIT_LABEL_TREE
,
518 strlen(GOT_COMMIT_LABEL_TREE
)) != 0 &&
519 strncmp(src
, GOT_COMMIT_LABEL_AUTHOR
,
520 strlen(GOT_COMMIT_LABEL_AUTHOR
)) != 0 &&
521 strncmp(src
, GOT_COMMIT_LABEL_PARENT
,
522 strlen(GOT_COMMIT_LABEL_PARENT
)) != 0 &&
523 strncmp(src
, GOT_COMMIT_LABEL_COMMITTER
,
524 strlen(GOT_COMMIT_LABEL_COMMITTER
)) != 0)
527 while (*src
!= '\0' && !eol
) {
539 if (strlcat(*logmsg
, src
, len
+ 1) >= len
+ 1) {
540 err
= got_error(GOT_ERR_NO_SPACE
);
544 /* Trim redundant trailing whitespace. */
545 len
= strlen(*logmsg
);
546 while (len
> 1 && isspace((unsigned char)(*logmsg
)[len
- 2]) &&
547 isspace((unsigned char)(*logmsg
)[len
- 1])) {
548 (*logmsg
)[len
- 1] = '\0';
552 /* Append a trailing newline if missing. */
553 if (len
> 0 && (*logmsg
)[len
- 1] != '\n') {
554 (*logmsg
)[len
] = '\n';
555 (*logmsg
)[len
+ 1] = '\0';
566 got_object_commit_get_logmsg_raw(struct got_commit_object
*commit
)
568 return commit
->logmsg
;
571 const struct got_error
*
572 got_object_parse_commit(struct got_commit_object
**commit
, char *buf
,
573 size_t len
, enum got_hash_algorithm algo
)
575 const struct got_error
*err
= NULL
;
577 size_t label_len
, digest_string_len
;
578 ssize_t remain
= (ssize_t
)len
;
580 digest_string_len
= got_hash_digest_string_length(algo
);
583 return got_error(GOT_ERR_BAD_OBJ_DATA
);
585 *commit
= got_object_commit_alloc_partial();
587 return got_error_from_errno("got_object_commit_alloc_partial");
589 label_len
= strlen(GOT_COMMIT_LABEL_TREE
);
590 if (strncmp(s
, GOT_COMMIT_LABEL_TREE
, label_len
) == 0) {
592 if (remain
< digest_string_len
) {
593 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
597 if (!got_parse_object_id((*commit
)->tree_id
, s
, algo
)) {
598 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
601 remain
-= digest_string_len
;
602 s
+= digest_string_len
;
604 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
608 label_len
= strlen(GOT_COMMIT_LABEL_PARENT
);
609 while (strncmp(s
, GOT_COMMIT_LABEL_PARENT
, label_len
) == 0) {
611 if (remain
< digest_string_len
) {
612 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
616 err
= got_object_commit_add_parent(*commit
, s
, algo
);
620 remain
-= digest_string_len
;
621 s
+= digest_string_len
;
624 label_len
= strlen(GOT_COMMIT_LABEL_AUTHOR
);
625 if (strncmp(s
, GOT_COMMIT_LABEL_AUTHOR
, label_len
) == 0) {
631 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
635 p
= memchr(s
, '\n', remain
);
637 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
642 err
= parse_commit_time(&(*commit
)->author_time
,
643 &(*commit
)->author_gmtoff
, s
);
646 (*commit
)->author
= strdup(s
);
647 if ((*commit
)->author
== NULL
) {
648 err
= got_error_from_errno("strdup");
655 label_len
= strlen(GOT_COMMIT_LABEL_COMMITTER
);
656 if (strncmp(s
, GOT_COMMIT_LABEL_COMMITTER
, label_len
) == 0) {
662 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
666 p
= memchr(s
, '\n', remain
);
668 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
673 err
= parse_commit_time(&(*commit
)->committer_time
,
674 &(*commit
)->committer_gmtoff
, s
);
677 (*commit
)->committer
= strdup(s
);
678 if ((*commit
)->committer
== NULL
) {
679 err
= got_error_from_errno("strdup");
686 (*commit
)->logmsg
= strndup(s
, remain
);
687 if ((*commit
)->logmsg
== NULL
) {
688 err
= got_error_from_errno("strndup");
693 got_object_commit_close(*commit
);
699 const struct got_error
*
700 got_object_read_commit(struct got_commit_object
**commit
, int fd
,
701 struct got_object_id
*expected_id
, size_t expected_size
)
703 struct got_object
*obj
= NULL
;
704 const struct got_error
*err
= NULL
;
707 struct got_inflate_checksum csum
;
709 struct got_object_id id
;
711 got_hash_init(&ctx
, expected_id
->algo
);
712 memset(&csum
, 0, sizeof(csum
));
713 csum
.output_ctx
= &ctx
;
715 err
= got_inflate_to_mem_fd(&p
, &len
, NULL
, &csum
, expected_size
, fd
);
719 got_hash_final_object_id(&ctx
, &id
);
720 if (got_object_id_cmp(expected_id
, &id
) != 0) {
721 err
= got_error_checksum(expected_id
);
725 err
= got_object_parse_header(&obj
, p
, len
);
729 if (len
< obj
->hdrlen
+ obj
->size
) {
730 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
734 if (obj
->type
!= GOT_OBJ_TYPE_COMMIT
) {
735 err
= got_error(GOT_ERR_OBJ_TYPE
);
739 /* Skip object header. */
741 err
= got_object_parse_commit(commit
, p
+ obj
->hdrlen
, len
,
746 got_object_close(obj
);
751 got_object_tree_close(struct got_tree_object
*tree
)
753 if (tree
->refcnt
> 0) {
755 if (tree
->refcnt
> 0)
763 const struct got_error
*
764 got_object_parse_tree_entry(struct got_parsed_tree_entry
*pte
, size_t *elen
,
765 char *buf
, size_t maxlen
, size_t digest_len
, enum got_hash_algorithm algo
)
771 *elen
= strnlen(buf
, maxlen
) + 1;
773 return got_error(GOT_ERR_BAD_OBJ_DATA
);
775 space
= memchr(buf
, ' ', *elen
);
776 if (space
== NULL
|| space
<= buf
)
777 return got_error(GOT_ERR_BAD_OBJ_DATA
);
782 if (*p
< '0' || *p
> '7')
783 return got_error(GOT_ERR_BAD_OBJ_DATA
);
785 pte
->mode
|= *p
- '0';
789 if (*elen
> maxlen
|| maxlen
- *elen
< digest_len
)
790 return got_error(GOT_ERR_BAD_OBJ_DATA
);
792 pte
->name
= space
+ 1;
793 pte
->namelen
= strlen(pte
->name
);
796 pte
->digest_len
= digest_len
;
803 pte_cmp(const void *pa
, const void *pb
)
805 const struct got_parsed_tree_entry
*a
= pa
, *b
= pb
;
807 return got_path_cmp(a
->name
, b
->name
, a
->namelen
, b
->namelen
);
810 const struct got_error
*
811 got_object_parse_tree(struct got_parsed_tree_entry
**entries
, size_t *nentries
,
812 size_t *nentries_alloc
, uint8_t *buf
, size_t len
,
813 enum got_hash_algorithm algo
)
815 const struct got_error
*err
= NULL
;
816 size_t digest_len
, remain
= len
;
817 const size_t nalloc
= 16;
818 struct got_parsed_tree_entry
*pte
;
821 digest_len
= got_hash_digest_length(algo
);
825 return NULL
; /* tree is empty */
830 if (*nentries
>= *nentries_alloc
) {
831 pte
= recallocarray(*entries
, *nentries_alloc
,
832 *nentries_alloc
+ nalloc
, sizeof(**entries
));
834 err
= got_error_from_errno("recallocarray");
838 *nentries_alloc
+= nalloc
;
841 pte
= &(*entries
)[*nentries
];
842 err
= got_object_parse_tree_entry(pte
, &elen
, buf
, remain
,
852 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
857 mergesort(*entries
, *nentries
, sizeof(**entries
), pte_cmp
);
859 for (i
= 0; i
< *nentries
- 1; i
++) {
860 struct got_parsed_tree_entry
*prev
= &(*entries
)[i
];
861 pte
= &(*entries
)[i
+ 1];
862 if (got_path_cmp(prev
->name
, pte
->name
,
863 prev
->namelen
, pte
->namelen
) == 0) {
864 err
= got_error(GOT_ERR_TREE_DUP_ENTRY
);
875 const struct got_error
*
876 got_object_read_tree(struct got_parsed_tree_entry
**entries
, size_t *nentries
,
877 size_t *nentries_alloc
, uint8_t **p
, int fd
,
878 struct got_object_id
*expected_id
)
880 const struct got_error
*err
= NULL
;
881 struct got_object
*obj
= NULL
;
883 struct got_inflate_checksum csum
;
885 struct got_object_id id
;
887 got_hash_init(&ctx
, expected_id
->algo
);
888 memset(&csum
, 0, sizeof(csum
));
889 csum
.output_ctx
= &ctx
;
891 err
= got_inflate_to_mem_fd(p
, &len
, NULL
, &csum
, 0, fd
);
895 got_hash_final_object_id(&ctx
, &id
);
896 if (got_object_id_cmp(expected_id
, &id
) != 0) {
897 err
= got_error_checksum(expected_id
);
901 err
= got_object_parse_header(&obj
, *p
, len
);
905 if (len
< obj
->hdrlen
+ obj
->size
) {
906 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
910 /* Skip object header. */
912 err
= got_object_parse_tree(entries
, nentries
, nentries_alloc
,
913 *p
+ obj
->hdrlen
, len
, expected_id
->algo
);
916 got_object_close(obj
);
921 got_object_tag_close(struct got_tag_object
*tag
)
923 if (tag
->refcnt
> 0) {
935 const struct got_error
*
936 got_object_parse_tag(struct got_tag_object
**tag
, uint8_t *buf
, size_t len
,
937 enum got_hash_algorithm algo
)
939 const struct got_error
*err
= NULL
;
942 size_t label_len
, digest_string_len
;
944 digest_string_len
= got_hash_digest_string_length(algo
);
947 return got_error(GOT_ERR_BAD_OBJ_DATA
);
949 *tag
= calloc(1, sizeof(**tag
));
951 return got_error_from_errno("calloc");
953 label_len
= strlen(GOT_TAG_LABEL_OBJECT
);
954 if (strncmp(s
, GOT_TAG_LABEL_OBJECT
, label_len
) == 0) {
956 if (remain
< digest_string_len
) {
957 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
961 if (!got_parse_object_id(&(*tag
)->id
, s
, algo
)) {
962 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
965 remain
-= digest_string_len
;
966 s
+= digest_string_len
;
968 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
973 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
977 label_len
= strlen(GOT_TAG_LABEL_TYPE
);
978 if (strncmp(s
, GOT_TAG_LABEL_TYPE
, label_len
) == 0) {
981 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
985 if (strncmp(s
, GOT_OBJ_LABEL_COMMIT
,
986 strlen(GOT_OBJ_LABEL_COMMIT
)) == 0) {
987 (*tag
)->obj_type
= GOT_OBJ_TYPE_COMMIT
;
988 label_len
= strlen(GOT_OBJ_LABEL_COMMIT
);
991 } else if (strncmp(s
, GOT_OBJ_LABEL_TREE
,
992 strlen(GOT_OBJ_LABEL_TREE
)) == 0) {
993 (*tag
)->obj_type
= GOT_OBJ_TYPE_TREE
;
994 label_len
= strlen(GOT_OBJ_LABEL_TREE
);
997 } else if (strncmp(s
, GOT_OBJ_LABEL_BLOB
,
998 strlen(GOT_OBJ_LABEL_BLOB
)) == 0) {
999 (*tag
)->obj_type
= GOT_OBJ_TYPE_BLOB
;
1000 label_len
= strlen(GOT_OBJ_LABEL_BLOB
);
1002 remain
-= label_len
;
1003 } else if (strncmp(s
, GOT_OBJ_LABEL_TAG
,
1004 strlen(GOT_OBJ_LABEL_TAG
)) == 0) {
1005 (*tag
)->obj_type
= GOT_OBJ_TYPE_TAG
;
1006 label_len
= strlen(GOT_OBJ_LABEL_TAG
);
1008 remain
-= label_len
;
1010 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1014 if (remain
<= 0 || *s
!= '\n') {
1015 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1021 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1025 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1029 label_len
= strlen(GOT_TAG_LABEL_TAG
);
1030 if (strncmp(s
, GOT_TAG_LABEL_TAG
, label_len
) == 0) {
1033 remain
-= label_len
;
1035 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1039 p
= memchr(s
, '\n', remain
);
1041 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1046 (*tag
)->tag
= strndup(s
, slen
);
1047 if ((*tag
)->tag
== NULL
) {
1048 err
= got_error_from_errno("strndup");
1054 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1058 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1062 label_len
= strlen(GOT_TAG_LABEL_TAGGER
);
1063 if (strncmp(s
, GOT_TAG_LABEL_TAGGER
, label_len
) == 0) {
1067 remain
-= label_len
;
1069 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1073 p
= memchr(s
, '\n', remain
);
1075 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1080 err
= parse_commit_time(&(*tag
)->tagger_time
,
1081 &(*tag
)->tagger_gmtoff
, s
);
1084 (*tag
)->tagger
= strdup(s
);
1085 if ((*tag
)->tagger
== NULL
) {
1086 err
= got_error_from_errno("strdup");
1092 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1096 /* Some old tags in the Linux git repo have no tagger. */
1097 (*tag
)->tagger
= strdup("");
1098 if ((*tag
)->tagger
== NULL
) {
1099 err
= got_error_from_errno("strdup");
1104 (*tag
)->tagmsg
= strndup(s
, remain
);
1105 if ((*tag
)->tagmsg
== NULL
) {
1106 err
= got_error_from_errno("strndup");
1111 got_object_tag_close(*tag
);
1117 const struct got_error
*
1118 got_object_read_tag(struct got_tag_object
**tag
, int fd
,
1119 struct got_object_id
*expected_id
, size_t expected_size
)
1121 const struct got_error
*err
= NULL
;
1122 struct got_object
*obj
= NULL
;
1125 struct got_inflate_checksum csum
;
1126 struct got_hash ctx
;
1127 struct got_object_id id
;
1129 got_hash_init(&ctx
, expected_id
->algo
);
1130 memset(&csum
, 0, sizeof(csum
));
1131 csum
.output_ctx
= &ctx
;
1133 err
= got_inflate_to_mem_fd(&p
, &len
, NULL
, &csum
,
1138 got_hash_final_object_id(&ctx
, &id
);
1139 if (got_object_id_cmp(expected_id
, &id
) != 0) {
1140 err
= got_error_checksum(expected_id
);
1144 err
= got_object_parse_header(&obj
, p
, len
);
1148 if (len
< obj
->hdrlen
+ obj
->size
) {
1149 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1153 /* Skip object header. */
1155 err
= got_object_parse_tag(tag
, p
+ obj
->hdrlen
, len
,
1160 got_object_close(obj
);