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
, GOT_HASH_SHA1
);
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");
289 err
= got_inflate_to_fd(&len
, f
, &csum
, outfd
);
294 if (len
< obj
->hdrlen
|| len
!= obj
->hdrlen
+ obj
->size
) {
295 err
= got_error(GOT_ERR_BAD_OBJ_HDR
);
299 got_hash_final_object_id(&ctx
, &id
);
300 if (got_object_id_cmp(expected_id
, &id
) != 0) {
301 err
= got_error_checksum(expected_id
);
306 *hdrlen
= obj
->hdrlen
;
308 got_object_close(obj
);
309 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
310 err
= got_error_from_errno("fclose");
314 struct got_commit_object
*
315 got_object_commit_alloc_partial(void)
317 struct got_commit_object
*commit
;
319 commit
= calloc(1, sizeof(*commit
));
322 commit
->tree_id
= malloc(sizeof(*commit
->tree_id
));
323 if (commit
->tree_id
== NULL
) {
328 STAILQ_INIT(&commit
->parent_ids
);
333 const struct got_error
*
334 got_object_commit_add_parent(struct got_commit_object
*commit
,
337 const struct got_error
*err
= NULL
;
338 struct got_object_qid
*qid
;
340 err
= got_object_qid_alloc_partial(&qid
);
344 if (!got_parse_object_id(&qid
->id
, id_str
, GOT_HASH_SHA1
)) {
345 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
346 got_object_qid_free(qid
);
350 STAILQ_INSERT_TAIL(&commit
->parent_ids
, qid
, entry
);
356 static const struct got_error
*
357 parse_gmtoff(time_t *gmtoff
, const char *tzstr
)
360 const char *p
= tzstr
;
368 return got_error(GOT_ERR_BAD_OBJ_DATA
);
370 if (!isdigit((unsigned char)*p
) &&
371 !isdigit((unsigned char)*(p
+ 1)))
372 return got_error(GOT_ERR_BAD_OBJ_DATA
);
373 h
= (((*p
- '0') * 10) + (*(p
+ 1) - '0'));
376 if (!isdigit((unsigned char)*p
) &&
377 !isdigit((unsigned char)*(p
+ 1)))
378 return got_error(GOT_ERR_BAD_OBJ_DATA
);
379 m
= ((*p
- '0') * 10) + (*(p
+ 1) - '0');
381 *gmtoff
= (h
* 60 * 60 + m
* 60) * sign
;
385 static const struct got_error
*
386 parse_commit_time(time_t *time
, time_t *gmtoff
, char *committer
)
388 const struct got_error
*err
= NULL
;
392 /* Parse and strip off trailing timezone indicator string. */
393 space
= strrchr(committer
, ' ');
395 return got_error(GOT_ERR_BAD_OBJ_DATA
);
396 tzstr
= strdup(space
+ 1);
398 return got_error_from_errno("strdup");
399 err
= parse_gmtoff(gmtoff
, tzstr
);
402 if (err
->code
!= GOT_ERR_BAD_OBJ_DATA
)
404 /* Old versions of Git omitted the timestamp. */
411 /* Timestamp is separated from committer name + email by space. */
412 space
= strrchr(committer
, ' ');
414 return got_error(GOT_ERR_BAD_OBJ_DATA
);
416 /* Timestamp parsed here is expressed as UNIX timestamp (UTC). */
417 *time
= strtonum(space
+ 1, 0, INT64_MAX
, &errstr
);
419 return got_error(GOT_ERR_BAD_OBJ_DATA
);
421 /* Strip off parsed time information, leaving just author and email. */
428 got_object_commit_close(struct got_commit_object
*commit
)
430 if (commit
->refcnt
> 0) {
432 if (commit
->refcnt
> 0)
436 got_object_id_queue_free(&commit
->parent_ids
);
437 free(commit
->tree_id
);
438 free(commit
->author
);
439 free(commit
->committer
);
440 free(commit
->logmsg
);
444 struct got_object_id
*
445 got_object_commit_get_tree_id(struct got_commit_object
*commit
)
447 return commit
->tree_id
;
451 got_object_commit_get_nparents(struct got_commit_object
*commit
)
453 return commit
->nparents
;
456 const struct got_object_id_queue
*
457 got_object_commit_get_parent_ids(struct got_commit_object
*commit
)
459 return &commit
->parent_ids
;
463 got_object_commit_get_author(struct got_commit_object
*commit
)
465 return commit
->author
;
469 got_object_commit_get_author_time(struct got_commit_object
*commit
)
471 return commit
->author_time
;
474 time_t got_object_commit_get_author_gmtoff(struct got_commit_object
*commit
)
476 return commit
->author_gmtoff
;
480 got_object_commit_get_committer(struct got_commit_object
*commit
)
482 return commit
->committer
;
486 got_object_commit_get_committer_time(struct got_commit_object
*commit
)
488 return commit
->committer_time
;
492 got_object_commit_get_committer_gmtoff(struct got_commit_object
*commit
)
494 return commit
->committer_gmtoff
;
497 const struct got_error
*
498 got_object_commit_get_logmsg(char **logmsg
, struct got_commit_object
*commit
)
500 const struct got_error
*err
= NULL
;
505 len
= strlen(commit
->logmsg
);
506 *logmsg
= malloc(len
+ 2); /* leave room for a trailing \n and \0 */
508 return got_error_from_errno("malloc");
511 * Strip out unusual headers. Headers are separated from the commit
512 * message body by a single empty line.
514 src
= commit
->logmsg
;
516 while (*src
!= '\0' && *src
!= '\n') {
517 int copy_header
= 1, eol
= 0;
518 if (strncmp(src
, GOT_COMMIT_LABEL_TREE
,
519 strlen(GOT_COMMIT_LABEL_TREE
)) != 0 &&
520 strncmp(src
, GOT_COMMIT_LABEL_AUTHOR
,
521 strlen(GOT_COMMIT_LABEL_AUTHOR
)) != 0 &&
522 strncmp(src
, GOT_COMMIT_LABEL_PARENT
,
523 strlen(GOT_COMMIT_LABEL_PARENT
)) != 0 &&
524 strncmp(src
, GOT_COMMIT_LABEL_COMMITTER
,
525 strlen(GOT_COMMIT_LABEL_COMMITTER
)) != 0)
528 while (*src
!= '\0' && !eol
) {
540 if (strlcat(*logmsg
, src
, len
+ 1) >= len
+ 1) {
541 err
= got_error(GOT_ERR_NO_SPACE
);
545 /* Trim redundant trailing whitespace. */
546 len
= strlen(*logmsg
);
547 while (len
> 1 && isspace((unsigned char)(*logmsg
)[len
- 2]) &&
548 isspace((unsigned char)(*logmsg
)[len
- 1])) {
549 (*logmsg
)[len
- 1] = '\0';
553 /* Append a trailing newline if missing. */
554 if (len
> 0 && (*logmsg
)[len
- 1] != '\n') {
555 (*logmsg
)[len
] = '\n';
556 (*logmsg
)[len
+ 1] = '\0';
567 got_object_commit_get_logmsg_raw(struct got_commit_object
*commit
)
569 return commit
->logmsg
;
572 const struct got_error
*
573 got_object_parse_commit(struct got_commit_object
**commit
, char *buf
,
576 const struct got_error
*err
= NULL
;
577 enum got_hash_algorithm algo
= GOT_HASH_SHA1
;
580 ssize_t remain
= (ssize_t
)len
;
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
< SHA1_DIGEST_STRING_LENGTH
) {
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
-= SHA1_DIGEST_STRING_LENGTH
;
602 s
+= SHA1_DIGEST_STRING_LENGTH
;
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
< SHA1_DIGEST_STRING_LENGTH
) {
612 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
616 err
= got_object_commit_add_parent(*commit
, s
);
620 remain
-= SHA1_DIGEST_STRING_LENGTH
;
621 s
+= SHA1_DIGEST_STRING_LENGTH
;
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
, GOT_HASH_SHA1
);
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
);
745 got_object_close(obj
);
750 got_object_tree_close(struct got_tree_object
*tree
)
752 if (tree
->refcnt
> 0) {
754 if (tree
->refcnt
> 0)
762 const struct got_error
*
763 got_object_parse_tree_entry(struct got_parsed_tree_entry
*pte
, size_t *elen
,
764 char *buf
, size_t maxlen
)
770 *elen
= strnlen(buf
, maxlen
) + 1;
772 return got_error(GOT_ERR_BAD_OBJ_DATA
);
774 space
= memchr(buf
, ' ', *elen
);
775 if (space
== NULL
|| space
<= buf
)
776 return got_error(GOT_ERR_BAD_OBJ_DATA
);
781 if (*p
< '0' || *p
> '7')
782 return got_error(GOT_ERR_BAD_OBJ_DATA
);
784 pte
->mode
|= *p
- '0';
788 if (*elen
> maxlen
|| maxlen
- *elen
< SHA1_DIGEST_LENGTH
)
789 return got_error(GOT_ERR_BAD_OBJ_DATA
);
791 pte
->name
= space
+ 1;
792 pte
->namelen
= strlen(pte
->name
);
795 *elen
+= SHA1_DIGEST_LENGTH
;
800 pte_cmp(const void *pa
, const void *pb
)
802 const struct got_parsed_tree_entry
*a
= pa
, *b
= pb
;
804 return got_path_cmp(a
->name
, b
->name
, a
->namelen
, b
->namelen
);
807 const struct got_error
*
808 got_object_parse_tree(struct got_parsed_tree_entry
**entries
, size_t *nentries
,
809 size_t *nentries_alloc
, uint8_t *buf
, size_t len
)
811 const struct got_error
*err
= NULL
;
813 const size_t nalloc
= 16;
814 struct got_parsed_tree_entry
*pte
;
819 return NULL
; /* tree is empty */
824 if (*nentries
>= *nentries_alloc
) {
825 pte
= recallocarray(*entries
, *nentries_alloc
,
826 *nentries_alloc
+ nalloc
, sizeof(**entries
));
828 err
= got_error_from_errno("recallocarray");
832 *nentries_alloc
+= nalloc
;
835 pte
= &(*entries
)[*nentries
];
836 err
= got_object_parse_tree_entry(pte
, &elen
, buf
, remain
);
845 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
850 mergesort(*entries
, *nentries
, sizeof(**entries
), pte_cmp
);
852 for (i
= 0; i
< *nentries
- 1; i
++) {
853 struct got_parsed_tree_entry
*prev
= &(*entries
)[i
];
854 pte
= &(*entries
)[i
+ 1];
855 if (got_path_cmp(prev
->name
, pte
->name
,
856 prev
->namelen
, pte
->namelen
) == 0) {
857 err
= got_error(GOT_ERR_TREE_DUP_ENTRY
);
868 const struct got_error
*
869 got_object_read_tree(struct got_parsed_tree_entry
**entries
, size_t *nentries
,
870 size_t *nentries_alloc
, uint8_t **p
, int fd
,
871 struct got_object_id
*expected_id
)
873 const struct got_error
*err
= NULL
;
874 struct got_object
*obj
= NULL
;
876 struct got_inflate_checksum csum
;
878 struct got_object_id id
;
880 got_hash_init(&ctx
, GOT_HASH_SHA1
);
881 memset(&csum
, 0, sizeof(csum
));
882 csum
.output_ctx
= &ctx
;
884 err
= got_inflate_to_mem_fd(p
, &len
, NULL
, &csum
, 0, fd
);
888 got_hash_final_object_id(&ctx
, &id
);
889 if (got_object_id_cmp(expected_id
, &id
) != 0) {
890 err
= got_error_checksum(expected_id
);
894 err
= got_object_parse_header(&obj
, *p
, len
);
898 if (len
< obj
->hdrlen
+ obj
->size
) {
899 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
903 /* Skip object header. */
905 err
= got_object_parse_tree(entries
, nentries
, nentries_alloc
,
906 *p
+ obj
->hdrlen
, len
);
909 got_object_close(obj
);
914 got_object_tag_close(struct got_tag_object
*tag
)
916 if (tag
->refcnt
> 0) {
928 const struct got_error
*
929 got_object_parse_tag(struct got_tag_object
**tag
, uint8_t *buf
, size_t len
)
931 const struct got_error
*err
= NULL
;
932 enum got_hash_algorithm algo
= GOT_HASH_SHA1
;
938 return got_error(GOT_ERR_BAD_OBJ_DATA
);
940 *tag
= calloc(1, sizeof(**tag
));
942 return got_error_from_errno("calloc");
944 label_len
= strlen(GOT_TAG_LABEL_OBJECT
);
945 if (strncmp(s
, GOT_TAG_LABEL_OBJECT
, label_len
) == 0) {
947 if (remain
< SHA1_DIGEST_STRING_LENGTH
) {
948 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
952 if (!got_parse_object_id(&(*tag
)->id
, s
, algo
)) {
953 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
956 remain
-= SHA1_DIGEST_STRING_LENGTH
;
957 s
+= SHA1_DIGEST_STRING_LENGTH
;
959 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
964 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
968 label_len
= strlen(GOT_TAG_LABEL_TYPE
);
969 if (strncmp(s
, GOT_TAG_LABEL_TYPE
, label_len
) == 0) {
972 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
976 if (strncmp(s
, GOT_OBJ_LABEL_COMMIT
,
977 strlen(GOT_OBJ_LABEL_COMMIT
)) == 0) {
978 (*tag
)->obj_type
= GOT_OBJ_TYPE_COMMIT
;
979 label_len
= strlen(GOT_OBJ_LABEL_COMMIT
);
982 } else if (strncmp(s
, GOT_OBJ_LABEL_TREE
,
983 strlen(GOT_OBJ_LABEL_TREE
)) == 0) {
984 (*tag
)->obj_type
= GOT_OBJ_TYPE_TREE
;
985 label_len
= strlen(GOT_OBJ_LABEL_TREE
);
988 } else if (strncmp(s
, GOT_OBJ_LABEL_BLOB
,
989 strlen(GOT_OBJ_LABEL_BLOB
)) == 0) {
990 (*tag
)->obj_type
= GOT_OBJ_TYPE_BLOB
;
991 label_len
= strlen(GOT_OBJ_LABEL_BLOB
);
994 } else if (strncmp(s
, GOT_OBJ_LABEL_TAG
,
995 strlen(GOT_OBJ_LABEL_TAG
)) == 0) {
996 (*tag
)->obj_type
= GOT_OBJ_TYPE_TAG
;
997 label_len
= strlen(GOT_OBJ_LABEL_TAG
);
1001 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1005 if (remain
<= 0 || *s
!= '\n') {
1006 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1012 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1016 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1020 label_len
= strlen(GOT_TAG_LABEL_TAG
);
1021 if (strncmp(s
, GOT_TAG_LABEL_TAG
, label_len
) == 0) {
1024 remain
-= label_len
;
1026 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1030 p
= memchr(s
, '\n', remain
);
1032 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1037 (*tag
)->tag
= strndup(s
, slen
);
1038 if ((*tag
)->tag
== NULL
) {
1039 err
= got_error_from_errno("strndup");
1045 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1049 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1053 label_len
= strlen(GOT_TAG_LABEL_TAGGER
);
1054 if (strncmp(s
, GOT_TAG_LABEL_TAGGER
, label_len
) == 0) {
1058 remain
-= label_len
;
1060 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1064 p
= memchr(s
, '\n', remain
);
1066 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1071 err
= parse_commit_time(&(*tag
)->tagger_time
,
1072 &(*tag
)->tagger_gmtoff
, s
);
1075 (*tag
)->tagger
= strdup(s
);
1076 if ((*tag
)->tagger
== NULL
) {
1077 err
= got_error_from_errno("strdup");
1083 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1087 /* Some old tags in the Linux git repo have no tagger. */
1088 (*tag
)->tagger
= strdup("");
1089 if ((*tag
)->tagger
== NULL
) {
1090 err
= got_error_from_errno("strdup");
1095 (*tag
)->tagmsg
= strndup(s
, remain
);
1096 if ((*tag
)->tagmsg
== NULL
) {
1097 err
= got_error_from_errno("strndup");
1102 got_object_tag_close(*tag
);
1108 const struct got_error
*
1109 got_object_read_tag(struct got_tag_object
**tag
, int fd
,
1110 struct got_object_id
*expected_id
, size_t expected_size
)
1112 const struct got_error
*err
= NULL
;
1113 struct got_object
*obj
= NULL
;
1116 struct got_inflate_checksum csum
;
1117 struct got_hash ctx
;
1118 struct got_object_id id
;
1120 got_hash_init(&ctx
, GOT_HASH_SHA1
);
1121 memset(&csum
, 0, sizeof(csum
));
1122 csum
.output_ctx
= &ctx
;
1124 err
= got_inflate_to_mem_fd(&p
, &len
, NULL
, &csum
,
1129 got_hash_final_object_id(&ctx
, &id
);
1130 if (got_object_id_cmp(expected_id
, &id
) != 0) {
1131 err
= got_error_checksum(expected_id
);
1135 err
= got_object_parse_header(&obj
, p
, len
);
1139 if (len
< obj
->hdrlen
+ obj
->size
) {
1140 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1144 /* Skip object header. */
1146 err
= got_object_parse_tag(tag
, p
+ obj
->hdrlen
, len
);
1150 got_object_close(obj
);