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_cache.h"
50 #include "got_lib_pack.h"
51 #include "got_lib_repository.h"
54 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
57 struct got_object_id
*
58 got_object_id_dup(struct got_object_id
*id1
)
60 struct got_object_id
*id2
;
62 id2
= malloc(sizeof(*id2
));
65 memcpy(id2
, id1
, sizeof(*id2
));
70 got_object_id_cmp(const struct got_object_id
*id1
,
71 const struct got_object_id
*id2
)
73 return memcmp(id1
->sha1
, id2
->sha1
, SHA1_DIGEST_LENGTH
);
76 const struct got_error
*
77 got_object_qid_alloc_partial(struct got_object_qid
**qid
)
79 *qid
= malloc(sizeof(**qid
));
81 return got_error_from_errno("malloc");
87 const struct got_error
*
88 got_object_id_str(char **outbuf
, struct got_object_id
*id
)
90 static const size_t len
= GOT_OBJECT_ID_HEX_MAXLEN
;
92 *outbuf
= malloc(len
);
94 return got_error_from_errno("malloc");
96 if (got_object_id_hex(id
, *outbuf
, len
) == NULL
) {
99 return got_error(GOT_ERR_BAD_OBJ_ID_STR
);
106 got_object_id_hex(struct got_object_id
*id
, char *buf
, size_t len
)
108 return got_sha1_digest_to_str(id
->sha1
, buf
, len
);
111 const struct got_error
*
112 got_object_type_label(const char **label
, int obj_type
)
114 const struct got_error
*err
= NULL
;
117 case GOT_OBJ_TYPE_BLOB
:
118 *label
= GOT_OBJ_LABEL_BLOB
;
120 case GOT_OBJ_TYPE_TREE
:
121 *label
= GOT_OBJ_LABEL_TREE
;
123 case GOT_OBJ_TYPE_COMMIT
:
124 *label
= GOT_OBJ_LABEL_COMMIT
;
126 case GOT_OBJ_TYPE_TAG
:
127 *label
= GOT_OBJ_LABEL_TAG
;
131 err
= got_error(GOT_ERR_OBJ_TYPE
);
139 got_object_close(struct got_object
*obj
)
141 if (obj
->refcnt
> 0) {
147 if (obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) {
148 struct got_delta
*delta
;
149 while (!STAILQ_EMPTY(&obj
->deltas
.entries
)) {
150 delta
= STAILQ_FIRST(&obj
->deltas
.entries
);
151 STAILQ_REMOVE_HEAD(&obj
->deltas
.entries
, entry
);
158 const struct got_error
*
159 got_object_raw_close(struct got_raw_object
*obj
)
161 const struct got_error
*err
= NULL
;
163 if (obj
->refcnt
> 0) {
172 if (obj
->f
== NULL
) {
174 if (munmap(obj
->data
, obj
->hdrlen
+ obj
->size
) == -1)
175 err
= got_error_from_errno("munmap");
176 if (close(obj
->fd
) == -1 && err
== NULL
)
177 err
= got_error_from_errno("close");
181 if (fclose(obj
->f
) == EOF
&& err
== NULL
)
182 err
= got_error_from_errno("fclose");
189 got_object_qid_free(struct got_object_qid
*qid
)
195 got_object_id_queue_free(struct got_object_id_queue
*ids
)
197 struct got_object_qid
*qid
;
199 while (!STAILQ_EMPTY(ids
)) {
200 qid
= STAILQ_FIRST(ids
);
201 STAILQ_REMOVE_HEAD(ids
, entry
);
202 got_object_qid_free(qid
);
206 const struct got_error
*
207 got_object_parse_header(struct got_object
**obj
, char *buf
, size_t len
)
209 const char *obj_labels
[] = {
210 GOT_OBJ_LABEL_COMMIT
,
215 const int obj_types
[] = {
228 end
= memchr(buf
, '\0', len
);
230 return got_error(GOT_ERR_BAD_OBJ_HDR
);
232 for (i
= 0; i
< nitems(obj_labels
); i
++) {
233 const char *label
= obj_labels
[i
];
234 size_t label_len
= strlen(label
);
237 if (len
<= label_len
|| buf
+ label_len
>= end
||
238 strncmp(buf
, label
, label_len
) != 0)
242 size
= strtonum(buf
+ label_len
, 0, LONG_MAX
, &errstr
);
244 return got_error(GOT_ERR_BAD_OBJ_HDR
);
249 return got_error(GOT_ERR_BAD_OBJ_HDR
);
251 *obj
= calloc(1, sizeof(**obj
));
253 return got_error_from_errno("calloc");
255 (*obj
)->hdrlen
= end
- buf
+ 1;
260 const struct got_error
*
261 got_object_read_header(struct got_object
**obj
, int fd
)
263 const struct got_error
*err
;
264 struct got_inflate_buf zb
;
266 const size_t zbsize
= 64;
267 size_t outlen
, totlen
;
272 buf
= malloc(zbsize
);
274 return got_error_from_errno("malloc");
277 err
= got_inflate_init(&zb
, buf
, zbsize
, NULL
);
283 err
= got_inflate_read_fd(&zb
, fd
, &outlen
, NULL
);
289 if (memchr(zb
.outbuf
, '\0', outlen
) == NULL
) {
292 newbuf
= recallocarray(buf
, nbuf
- 1, nbuf
, zbsize
);
293 if (newbuf
== NULL
) {
294 err
= got_error_from_errno("recallocarray");
298 zb
.outbuf
= newbuf
+ totlen
;
299 zb
.outlen
= (nbuf
* zbsize
) - totlen
;
301 } while (memchr(zb
.outbuf
, '\0', outlen
) == NULL
);
303 err
= got_object_parse_header(obj
, buf
, totlen
);
306 got_inflate_end(&zb
);
310 const struct got_error
*
311 got_object_read_raw(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
312 size_t max_in_mem_size
, int outfd
, struct got_object_id
*expected_id
,
315 const struct got_error
*err
= NULL
;
316 struct got_object
*obj
;
317 struct got_inflate_checksum csum
;
318 struct got_object_id id
;
320 size_t len
, consumed
;
327 got_hash_init(&ctx
, GOT_HASH_SHA1
);
328 memset(&csum
, 0, sizeof(csum
));
329 csum
.output_ctx
= &ctx
;
331 if (lseek(infd
, SEEK_SET
, 0) == -1)
332 return got_error_from_errno("lseek");
334 err
= got_object_read_header(&obj
, infd
);
338 if (lseek(infd
, SEEK_SET
, 0) == -1)
339 return got_error_from_errno("lseek");
341 if (obj
->size
+ obj
->hdrlen
<= max_in_mem_size
) {
342 err
= got_inflate_to_mem_fd(outbuf
, &len
, &consumed
, &csum
,
343 obj
->size
+ obj
->hdrlen
, infd
);
347 * XXX This uses an extra file descriptor for no good reason.
348 * We should have got_inflate_fd_to_fd().
352 return got_error_from_errno("dup");
355 err
= got_error_from_errno("fdopen");
360 err
= got_inflate_to_fd(&len
, f
, &csum
, outfd
);
365 if (len
< obj
->hdrlen
|| len
!= obj
->hdrlen
+ obj
->size
) {
366 err
= got_error(GOT_ERR_BAD_OBJ_HDR
);
370 got_hash_final_object_id(&ctx
, &id
);
371 if (got_object_id_cmp(expected_id
, &id
) != 0) {
372 err
= got_error_checksum(expected_id
);
377 *hdrlen
= obj
->hdrlen
;
379 got_object_close(obj
);
380 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
381 err
= got_error_from_errno("fclose");
385 struct got_commit_object
*
386 got_object_commit_alloc_partial(void)
388 struct got_commit_object
*commit
;
390 commit
= calloc(1, sizeof(*commit
));
393 commit
->tree_id
= malloc(sizeof(*commit
->tree_id
));
394 if (commit
->tree_id
== NULL
) {
399 STAILQ_INIT(&commit
->parent_ids
);
404 const struct got_error
*
405 got_object_commit_add_parent(struct got_commit_object
*commit
,
408 const struct got_error
*err
= NULL
;
409 struct got_object_qid
*qid
;
411 err
= got_object_qid_alloc_partial(&qid
);
415 if (!got_parse_object_id(&qid
->id
, id_str
, GOT_HASH_SHA1
)) {
416 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
417 got_object_qid_free(qid
);
421 STAILQ_INSERT_TAIL(&commit
->parent_ids
, qid
, entry
);
427 static const struct got_error
*
428 parse_gmtoff(time_t *gmtoff
, const char *tzstr
)
431 const char *p
= tzstr
;
439 return got_error(GOT_ERR_BAD_OBJ_DATA
);
441 if (!isdigit((unsigned char)*p
) &&
442 !isdigit((unsigned char)*(p
+ 1)))
443 return got_error(GOT_ERR_BAD_OBJ_DATA
);
444 h
= (((*p
- '0') * 10) + (*(p
+ 1) - '0'));
447 if (!isdigit((unsigned char)*p
) &&
448 !isdigit((unsigned char)*(p
+ 1)))
449 return got_error(GOT_ERR_BAD_OBJ_DATA
);
450 m
= ((*p
- '0') * 10) + (*(p
+ 1) - '0');
452 *gmtoff
= (h
* 60 * 60 + m
* 60) * sign
;
456 static const struct got_error
*
457 parse_commit_time(time_t *time
, time_t *gmtoff
, char *committer
)
459 const struct got_error
*err
= NULL
;
463 /* Parse and strip off trailing timezone indicator string. */
464 space
= strrchr(committer
, ' ');
466 return got_error(GOT_ERR_BAD_OBJ_DATA
);
467 tzstr
= strdup(space
+ 1);
469 return got_error_from_errno("strdup");
470 err
= parse_gmtoff(gmtoff
, tzstr
);
473 if (err
->code
!= GOT_ERR_BAD_OBJ_DATA
)
475 /* Old versions of Git omitted the timestamp. */
482 /* Timestamp is separated from committer name + email by space. */
483 space
= strrchr(committer
, ' ');
485 return got_error(GOT_ERR_BAD_OBJ_DATA
);
487 /* Timestamp parsed here is expressed as UNIX timestamp (UTC). */
488 *time
= strtonum(space
+ 1, 0, INT64_MAX
, &errstr
);
490 return got_error(GOT_ERR_BAD_OBJ_DATA
);
492 /* Strip off parsed time information, leaving just author and email. */
499 got_object_commit_close(struct got_commit_object
*commit
)
501 if (commit
->refcnt
> 0) {
503 if (commit
->refcnt
> 0)
507 got_object_id_queue_free(&commit
->parent_ids
);
508 free(commit
->tree_id
);
509 free(commit
->author
);
510 free(commit
->committer
);
511 free(commit
->logmsg
);
515 struct got_object_id
*
516 got_object_commit_get_tree_id(struct got_commit_object
*commit
)
518 return commit
->tree_id
;
522 got_object_commit_get_nparents(struct got_commit_object
*commit
)
524 return commit
->nparents
;
527 const struct got_object_id_queue
*
528 got_object_commit_get_parent_ids(struct got_commit_object
*commit
)
530 return &commit
->parent_ids
;
534 got_object_commit_get_author(struct got_commit_object
*commit
)
536 return commit
->author
;
540 got_object_commit_get_author_time(struct got_commit_object
*commit
)
542 return commit
->author_time
;
545 time_t got_object_commit_get_author_gmtoff(struct got_commit_object
*commit
)
547 return commit
->author_gmtoff
;
551 got_object_commit_get_committer(struct got_commit_object
*commit
)
553 return commit
->committer
;
557 got_object_commit_get_committer_time(struct got_commit_object
*commit
)
559 return commit
->committer_time
;
563 got_object_commit_get_committer_gmtoff(struct got_commit_object
*commit
)
565 return commit
->committer_gmtoff
;
568 const struct got_error
*
569 got_object_commit_get_logmsg(char **logmsg
, struct got_commit_object
*commit
)
571 const struct got_error
*err
= NULL
;
576 len
= strlen(commit
->logmsg
);
577 *logmsg
= malloc(len
+ 2); /* leave room for a trailing \n and \0 */
579 return got_error_from_errno("malloc");
582 * Strip out unusual headers. Headers are separated from the commit
583 * message body by a single empty line.
585 src
= commit
->logmsg
;
587 while (*src
!= '\0' && *src
!= '\n') {
588 int copy_header
= 1, eol
= 0;
589 if (strncmp(src
, GOT_COMMIT_LABEL_TREE
,
590 strlen(GOT_COMMIT_LABEL_TREE
)) != 0 &&
591 strncmp(src
, GOT_COMMIT_LABEL_AUTHOR
,
592 strlen(GOT_COMMIT_LABEL_AUTHOR
)) != 0 &&
593 strncmp(src
, GOT_COMMIT_LABEL_PARENT
,
594 strlen(GOT_COMMIT_LABEL_PARENT
)) != 0 &&
595 strncmp(src
, GOT_COMMIT_LABEL_COMMITTER
,
596 strlen(GOT_COMMIT_LABEL_COMMITTER
)) != 0)
599 while (*src
!= '\0' && !eol
) {
611 if (strlcat(*logmsg
, src
, len
+ 1) >= len
+ 1) {
612 err
= got_error(GOT_ERR_NO_SPACE
);
616 /* Trim redundant trailing whitespace. */
617 len
= strlen(*logmsg
);
618 while (len
> 1 && isspace((unsigned char)(*logmsg
)[len
- 2]) &&
619 isspace((unsigned char)(*logmsg
)[len
- 1])) {
620 (*logmsg
)[len
- 1] = '\0';
624 /* Append a trailing newline if missing. */
625 if (len
> 0 && (*logmsg
)[len
- 1] != '\n') {
626 (*logmsg
)[len
] = '\n';
627 (*logmsg
)[len
+ 1] = '\0';
638 got_object_commit_get_logmsg_raw(struct got_commit_object
*commit
)
640 return commit
->logmsg
;
643 const struct got_error
*
644 got_object_parse_commit(struct got_commit_object
**commit
, char *buf
,
647 const struct got_error
*err
= NULL
;
648 enum got_hash_algorithm algo
= GOT_HASH_SHA1
;
651 ssize_t remain
= (ssize_t
)len
;
654 return got_error(GOT_ERR_BAD_OBJ_DATA
);
656 *commit
= got_object_commit_alloc_partial();
658 return got_error_from_errno("got_object_commit_alloc_partial");
660 label_len
= strlen(GOT_COMMIT_LABEL_TREE
);
661 if (strncmp(s
, GOT_COMMIT_LABEL_TREE
, label_len
) == 0) {
663 if (remain
< SHA1_DIGEST_STRING_LENGTH
) {
664 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
668 if (!got_parse_object_id((*commit
)->tree_id
, s
, algo
)) {
669 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
672 remain
-= SHA1_DIGEST_STRING_LENGTH
;
673 s
+= SHA1_DIGEST_STRING_LENGTH
;
675 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
679 label_len
= strlen(GOT_COMMIT_LABEL_PARENT
);
680 while (strncmp(s
, GOT_COMMIT_LABEL_PARENT
, label_len
) == 0) {
682 if (remain
< SHA1_DIGEST_STRING_LENGTH
) {
683 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
687 err
= got_object_commit_add_parent(*commit
, s
);
691 remain
-= SHA1_DIGEST_STRING_LENGTH
;
692 s
+= SHA1_DIGEST_STRING_LENGTH
;
695 label_len
= strlen(GOT_COMMIT_LABEL_AUTHOR
);
696 if (strncmp(s
, GOT_COMMIT_LABEL_AUTHOR
, label_len
) == 0) {
702 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
706 p
= memchr(s
, '\n', remain
);
708 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
713 err
= parse_commit_time(&(*commit
)->author_time
,
714 &(*commit
)->author_gmtoff
, s
);
717 (*commit
)->author
= strdup(s
);
718 if ((*commit
)->author
== NULL
) {
719 err
= got_error_from_errno("strdup");
726 label_len
= strlen(GOT_COMMIT_LABEL_COMMITTER
);
727 if (strncmp(s
, GOT_COMMIT_LABEL_COMMITTER
, label_len
) == 0) {
733 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
737 p
= memchr(s
, '\n', remain
);
739 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
744 err
= parse_commit_time(&(*commit
)->committer_time
,
745 &(*commit
)->committer_gmtoff
, s
);
748 (*commit
)->committer
= strdup(s
);
749 if ((*commit
)->committer
== NULL
) {
750 err
= got_error_from_errno("strdup");
757 (*commit
)->logmsg
= strndup(s
, remain
);
758 if ((*commit
)->logmsg
== NULL
) {
759 err
= got_error_from_errno("strndup");
764 got_object_commit_close(*commit
);
770 const struct got_error
*
771 got_object_read_commit(struct got_commit_object
**commit
, int fd
,
772 struct got_object_id
*expected_id
, size_t expected_size
)
774 struct got_object
*obj
= NULL
;
775 const struct got_error
*err
= NULL
;
778 struct got_inflate_checksum csum
;
780 struct got_object_id id
;
782 got_hash_init(&ctx
, GOT_HASH_SHA1
);
783 memset(&csum
, 0, sizeof(csum
));
784 csum
.output_ctx
= &ctx
;
786 err
= got_inflate_to_mem_fd(&p
, &len
, NULL
, &csum
, expected_size
, fd
);
790 got_hash_final_object_id(&ctx
, &id
);
791 if (got_object_id_cmp(expected_id
, &id
) != 0) {
792 err
= got_error_checksum(expected_id
);
796 err
= got_object_parse_header(&obj
, p
, len
);
800 if (len
< obj
->hdrlen
+ obj
->size
) {
801 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
805 if (obj
->type
!= GOT_OBJ_TYPE_COMMIT
) {
806 err
= got_error(GOT_ERR_OBJ_TYPE
);
810 /* Skip object header. */
812 err
= got_object_parse_commit(commit
, p
+ obj
->hdrlen
, len
);
816 got_object_close(obj
);
821 got_object_tree_close(struct got_tree_object
*tree
)
823 if (tree
->refcnt
> 0) {
825 if (tree
->refcnt
> 0)
833 static const struct got_error
*
834 parse_tree_entry(struct got_parsed_tree_entry
*pte
, size_t *elen
, char *buf
,
841 *elen
= strnlen(buf
, maxlen
) + 1;
843 return got_error(GOT_ERR_BAD_OBJ_DATA
);
845 space
= memchr(buf
, ' ', *elen
);
846 if (space
== NULL
|| space
<= buf
)
847 return got_error(GOT_ERR_BAD_OBJ_DATA
);
852 if (*p
< '0' || *p
> '7')
853 return got_error(GOT_ERR_BAD_OBJ_DATA
);
855 pte
->mode
|= *p
- '0';
859 if (*elen
> maxlen
|| maxlen
- *elen
< SHA1_DIGEST_LENGTH
)
860 return got_error(GOT_ERR_BAD_OBJ_DATA
);
862 pte
->name
= space
+ 1;
863 pte
->namelen
= strlen(pte
->name
);
866 *elen
+= SHA1_DIGEST_LENGTH
;
871 pte_cmp(const void *pa
, const void *pb
)
873 const struct got_parsed_tree_entry
*a
= pa
, *b
= pb
;
875 return got_path_cmp(a
->name
, b
->name
, a
->namelen
, b
->namelen
);
878 const struct got_error
*
879 got_object_parse_tree(struct got_parsed_tree_entry
**entries
, size_t *nentries
,
880 size_t *nentries_alloc
, uint8_t *buf
, size_t len
)
882 const struct got_error
*err
= NULL
;
884 const size_t nalloc
= 16;
885 struct got_parsed_tree_entry
*pte
;
890 return NULL
; /* tree is empty */
895 if (*nentries
>= *nentries_alloc
) {
896 pte
= recallocarray(*entries
, *nentries_alloc
,
897 *nentries_alloc
+ nalloc
, sizeof(**entries
));
899 err
= got_error_from_errno("recallocarray");
903 *nentries_alloc
+= nalloc
;
906 pte
= &(*entries
)[*nentries
];
907 err
= parse_tree_entry(pte
, &elen
, buf
, remain
);
916 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
921 mergesort(*entries
, *nentries
, sizeof(**entries
), pte_cmp
);
923 for (i
= 0; i
< *nentries
- 1; i
++) {
924 struct got_parsed_tree_entry
*prev
= &(*entries
)[i
];
925 pte
= &(*entries
)[i
+ 1];
926 if (got_path_cmp(prev
->name
, pte
->name
,
927 prev
->namelen
, pte
->namelen
) == 0) {
928 err
= got_error(GOT_ERR_TREE_DUP_ENTRY
);
939 const struct got_error
*
940 got_object_read_tree(struct got_parsed_tree_entry
**entries
, size_t *nentries
,
941 size_t *nentries_alloc
, uint8_t **p
, int fd
,
942 struct got_object_id
*expected_id
)
944 const struct got_error
*err
= NULL
;
945 struct got_object
*obj
= NULL
;
947 struct got_inflate_checksum csum
;
949 struct got_object_id id
;
951 got_hash_init(&ctx
, GOT_HASH_SHA1
);
952 memset(&csum
, 0, sizeof(csum
));
953 csum
.output_ctx
= &ctx
;
955 err
= got_inflate_to_mem_fd(p
, &len
, NULL
, &csum
, 0, fd
);
959 got_hash_final_object_id(&ctx
, &id
);
960 if (got_object_id_cmp(expected_id
, &id
) != 0) {
961 err
= got_error_checksum(expected_id
);
965 err
= got_object_parse_header(&obj
, *p
, len
);
969 if (len
< obj
->hdrlen
+ obj
->size
) {
970 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
974 /* Skip object header. */
976 err
= got_object_parse_tree(entries
, nentries
, nentries_alloc
,
977 *p
+ obj
->hdrlen
, len
);
980 got_object_close(obj
);
985 got_object_tag_close(struct got_tag_object
*tag
)
987 if (tag
->refcnt
> 0) {
999 const struct got_error
*
1000 got_object_parse_tag(struct got_tag_object
**tag
, uint8_t *buf
, size_t len
)
1002 const struct got_error
*err
= NULL
;
1003 enum got_hash_algorithm algo
= GOT_HASH_SHA1
;
1004 size_t remain
= len
;
1009 return got_error(GOT_ERR_BAD_OBJ_DATA
);
1011 *tag
= calloc(1, sizeof(**tag
));
1013 return got_error_from_errno("calloc");
1015 label_len
= strlen(GOT_TAG_LABEL_OBJECT
);
1016 if (strncmp(s
, GOT_TAG_LABEL_OBJECT
, label_len
) == 0) {
1017 remain
-= label_len
;
1018 if (remain
< SHA1_DIGEST_STRING_LENGTH
) {
1019 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1023 if (!got_parse_object_id(&(*tag
)->id
, s
, algo
)) {
1024 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1027 remain
-= SHA1_DIGEST_STRING_LENGTH
;
1028 s
+= SHA1_DIGEST_STRING_LENGTH
;
1030 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1035 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1039 label_len
= strlen(GOT_TAG_LABEL_TYPE
);
1040 if (strncmp(s
, GOT_TAG_LABEL_TYPE
, label_len
) == 0) {
1041 remain
-= label_len
;
1043 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1047 if (strncmp(s
, GOT_OBJ_LABEL_COMMIT
,
1048 strlen(GOT_OBJ_LABEL_COMMIT
)) == 0) {
1049 (*tag
)->obj_type
= GOT_OBJ_TYPE_COMMIT
;
1050 label_len
= strlen(GOT_OBJ_LABEL_COMMIT
);
1052 remain
-= label_len
;
1053 } else if (strncmp(s
, GOT_OBJ_LABEL_TREE
,
1054 strlen(GOT_OBJ_LABEL_TREE
)) == 0) {
1055 (*tag
)->obj_type
= GOT_OBJ_TYPE_TREE
;
1056 label_len
= strlen(GOT_OBJ_LABEL_TREE
);
1058 remain
-= label_len
;
1059 } else if (strncmp(s
, GOT_OBJ_LABEL_BLOB
,
1060 strlen(GOT_OBJ_LABEL_BLOB
)) == 0) {
1061 (*tag
)->obj_type
= GOT_OBJ_TYPE_BLOB
;
1062 label_len
= strlen(GOT_OBJ_LABEL_BLOB
);
1064 remain
-= label_len
;
1065 } else if (strncmp(s
, GOT_OBJ_LABEL_TAG
,
1066 strlen(GOT_OBJ_LABEL_TAG
)) == 0) {
1067 (*tag
)->obj_type
= GOT_OBJ_TYPE_TAG
;
1068 label_len
= strlen(GOT_OBJ_LABEL_TAG
);
1070 remain
-= label_len
;
1072 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1076 if (remain
<= 0 || *s
!= '\n') {
1077 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1083 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1087 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1091 label_len
= strlen(GOT_TAG_LABEL_TAG
);
1092 if (strncmp(s
, GOT_TAG_LABEL_TAG
, label_len
) == 0) {
1095 remain
-= label_len
;
1097 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1101 p
= memchr(s
, '\n', remain
);
1103 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1108 (*tag
)->tag
= strndup(s
, slen
);
1109 if ((*tag
)->tag
== NULL
) {
1110 err
= got_error_from_errno("strndup");
1116 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1120 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1124 label_len
= strlen(GOT_TAG_LABEL_TAGGER
);
1125 if (strncmp(s
, GOT_TAG_LABEL_TAGGER
, label_len
) == 0) {
1129 remain
-= label_len
;
1131 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1135 p
= memchr(s
, '\n', remain
);
1137 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1142 err
= parse_commit_time(&(*tag
)->tagger_time
,
1143 &(*tag
)->tagger_gmtoff
, s
);
1146 (*tag
)->tagger
= strdup(s
);
1147 if ((*tag
)->tagger
== NULL
) {
1148 err
= got_error_from_errno("strdup");
1154 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1158 /* Some old tags in the Linux git repo have no tagger. */
1159 (*tag
)->tagger
= strdup("");
1160 if ((*tag
)->tagger
== NULL
) {
1161 err
= got_error_from_errno("strdup");
1166 (*tag
)->tagmsg
= strndup(s
, remain
);
1167 if ((*tag
)->tagmsg
== NULL
) {
1168 err
= got_error_from_errno("strndup");
1173 got_object_tag_close(*tag
);
1179 const struct got_error
*
1180 got_object_read_tag(struct got_tag_object
**tag
, int fd
,
1181 struct got_object_id
*expected_id
, size_t expected_size
)
1183 const struct got_error
*err
= NULL
;
1184 struct got_object
*obj
= NULL
;
1187 struct got_inflate_checksum csum
;
1188 struct got_hash ctx
;
1189 struct got_object_id id
;
1191 got_hash_init(&ctx
, GOT_HASH_SHA1
);
1192 memset(&csum
, 0, sizeof(csum
));
1193 csum
.output_ctx
= &ctx
;
1195 err
= got_inflate_to_mem_fd(&p
, &len
, NULL
, &csum
,
1200 got_hash_final_object_id(&ctx
, &id
);
1201 if (got_object_id_cmp(expected_id
, &id
) != 0) {
1202 err
= got_error_checksum(expected_id
);
1206 err
= got_object_parse_header(&obj
, p
, len
);
1210 if (len
< obj
->hdrlen
+ obj
->size
) {
1211 err
= got_error(GOT_ERR_BAD_OBJ_DATA
);
1215 /* Skip object header. */
1217 err
= got_object_parse_tag(tag
, p
+ obj
->hdrlen
, len
);
1221 got_object_close(obj
);
1225 const struct got_error
*
1226 got_read_file_to_mem(uint8_t **outbuf
, size_t *outlen
, FILE *f
)
1228 const struct got_error
*err
= NULL
;
1229 static const size_t blocksize
= 512;
1230 size_t n
, total
, remain
;
1236 buf
= malloc(blocksize
);
1238 return got_error_from_errno("malloc");
1245 newbuf
= reallocarray(buf
, 1, total
+ blocksize
);
1246 if (newbuf
== NULL
) {
1247 err
= got_error_from_errno("reallocarray");
1251 remain
+= blocksize
;
1253 n
= fread(buf
+ total
, 1, remain
, f
);
1256 err
= got_ferror(f
, GOT_ERR_IO
);