Bug Summary

File:got/../lib/object_parse.c
Warning:line 286, column 29
Access to field 'id' results in a dereference of a null pointer (loaded from variable 'qid')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd6.9 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name object_parse.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/local/lib/clang/11.1.0 -I /home/ben/Projects/got/got/../include -I /home/ben/Projects/got/got/../lib -D GOT_LIBEXECDIR=/home/ben/bin -D GOT_VERSION=0.53-current -internal-isystem /usr/local/lib/clang/11.1.0/include -internal-externc-isystem /usr/include -O0 -fdebug-compilation-dir /home/ben/Projects/got/got/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/got/scan/2021-05-28-230913-68537-1 -x c /home/ben/Projects/got/got/../lib/object_parse.c
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 */
16
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/queue.h>
20#include <sys/uio.h>
21#include <sys/socket.h>
22#include <sys/wait.h>
23
24#include <errno(*__errno()).h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <stdint.h>
29#include <sha1.h>
30#include <zlib.h>
31#include <ctype.h>
32#include <limits.h>
33#include <imsg.h>
34#include <time.h>
35#include <unistd.h>
36
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"
42
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"
52
53#ifndef nitems
54#define nitems(_a)(sizeof(_a) / sizeof((_a)[0])) (sizeof(_a) / sizeof((_a)[0]))
55#endif
56
57struct got_object_id *
58got_object_id_dup(struct got_object_id *id1)
59{
60 struct got_object_id *id2;
61
62 id2 = malloc(sizeof(*id2));
63 if (id2 == NULL((void *)0))
64 return NULL((void *)0);
65 memcpy(id2, id1, sizeof(*id2));
66 return id2;
67}
68
69int
70got_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_LENGTH20);
74}
75
76const struct got_error *
77got_object_qid_alloc_partial(struct got_object_qid **qid)
78{
79 const struct got_error *err = NULL((void *)0);
80
81 *qid = malloc(sizeof(**qid));
82 if (*qid == NULL((void *)0))
14
Assuming the condition is false
15
Taking false branch
83 return got_error_from_errno("malloc");
84
85 (*qid)->id = malloc(sizeof(*((*qid)->id)));
86 if ((*qid)->id == NULL((void *)0)) {
16
Assuming field 'id' is equal to NULL
17
Taking true branch
87 err = got_error_from_errno("malloc");
88 got_object_qid_free(*qid);
89 *qid = NULL((void *)0);
18
Null pointer value stored to 'qid'
90 return err;
19
Returning pointer (loaded from 'err'), which participates in a condition later
91 }
92
93 return NULL((void *)0);
94}
95
96const struct got_error *
97got_object_id_str(char **outbuf, struct got_object_id *id)
98{
99 static const size_t len = SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1);
100
101 *outbuf = malloc(len);
102 if (*outbuf == NULL((void *)0))
103 return got_error_from_errno("malloc");
104
105 if (got_sha1_digest_to_str(id->sha1, *outbuf, len) == NULL((void *)0)) {
106 free(*outbuf);
107 *outbuf = NULL((void *)0);
108 return got_error(GOT_ERR_BAD_OBJ_ID_STR23);
109 }
110
111 return NULL((void *)0);
112}
113
114void
115got_object_close(struct got_object *obj)
116{
117 if (obj->refcnt > 0) {
118 obj->refcnt--;
119 if (obj->refcnt > 0)
120 return;
121 }
122
123 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED0x02) {
124 struct got_delta *delta;
125 while (!SIMPLEQ_EMPTY(&obj->deltas.entries)(((&obj->deltas.entries)->sqh_first) == ((void *)0)
)
) {
126 delta = SIMPLEQ_FIRST(&obj->deltas.entries)((&obj->deltas.entries)->sqh_first);
127 SIMPLEQ_REMOVE_HEAD(&obj->deltas.entries, entry)do { if (((&obj->deltas.entries)->sqh_first = (&
obj->deltas.entries)->sqh_first->entry.sqe_next) == (
(void *)0)) (&obj->deltas.entries)->sqh_last = &
(&obj->deltas.entries)->sqh_first; } while (0)
;
128 free(delta);
129 }
130 }
131 free(obj);
132}
133
134void
135got_object_qid_free(struct got_object_qid *qid)
136{
137 free(qid->id);
138 free(qid);
139}
140
141void
142got_object_id_queue_free(struct got_object_id_queue *ids)
143{
144 struct got_object_qid *qid;
145
146 while (!SIMPLEQ_EMPTY(ids)(((ids)->sqh_first) == ((void *)0))) {
147 qid = SIMPLEQ_FIRST(ids)((ids)->sqh_first);
148 SIMPLEQ_REMOVE_HEAD(ids, entry)do { if (((ids)->sqh_first = (ids)->sqh_first->entry
.sqe_next) == ((void *)0)) (ids)->sqh_last = &(ids)->
sqh_first; } while (0)
;
149 got_object_qid_free(qid);
150 }
151}
152
153const struct got_error *
154got_object_parse_header(struct got_object **obj, char *buf, size_t len)
155{
156 const char *obj_labels[] = {
157 GOT_OBJ_LABEL_COMMIT"commit",
158 GOT_OBJ_LABEL_TREE"tree",
159 GOT_OBJ_LABEL_BLOB"blob",
160 GOT_OBJ_LABEL_TAG"tag",
161 };
162 const int obj_types[] = {
163 GOT_OBJ_TYPE_COMMIT1,
164 GOT_OBJ_TYPE_TREE2,
165 GOT_OBJ_TYPE_BLOB3,
166 GOT_OBJ_TYPE_TAG4,
167 };
168 int type = 0;
169 size_t size = 0, hdrlen = 0;
170 size_t i;
171
172 *obj = NULL((void *)0);
173
174 hdrlen = strnlen(buf, len) + 1 /* '\0' */;
175 if (hdrlen > len)
176 return got_error(GOT_ERR_BAD_OBJ_HDR10);
177
178 for (i = 0; i < nitems(obj_labels)(sizeof(obj_labels) / sizeof((obj_labels)[0])); i++) {
179 const char *label = obj_labels[i];
180 size_t label_len = strlen(label);
181 const char *errstr;
182
183 if (strncmp(buf, label, label_len) != 0)
184 continue;
185
186 type = obj_types[i];
187 if (len <= label_len)
188 return got_error(GOT_ERR_BAD_OBJ_HDR10);
189 size = strtonum(buf + label_len, 0, LONG_MAX9223372036854775807L, &errstr);
190 if (errstr != NULL((void *)0))
191 return got_error(GOT_ERR_BAD_OBJ_HDR10);
192 break;
193 }
194
195 if (type == 0)
196 return got_error(GOT_ERR_BAD_OBJ_HDR10);
197
198 *obj = calloc(1, sizeof(**obj));
199 if (*obj == NULL((void *)0))
200 return got_error_from_errno("calloc");
201 (*obj)->type = type;
202 (*obj)->hdrlen = hdrlen;
203 (*obj)->size = size;
204 return NULL((void *)0);
205}
206
207const struct got_error *
208got_object_read_header(struct got_object **obj, int fd)
209{
210 const struct got_error *err;
211 struct got_inflate_buf zb;
212 char *buf;
213 const size_t zbsize = 64;
214 size_t outlen, totlen;
215 int nbuf = 1;
216
217 *obj = NULL((void *)0);
218
219 buf = malloc(zbsize);
220 if (buf == NULL((void *)0))
221 return got_error_from_errno("malloc");
222
223 err = got_inflate_init(&zb, buf, zbsize, NULL((void *)0));
224 if (err)
225 return err;
226
227 totlen = 0;
228 do {
229 err = got_inflate_read_fd(&zb, fd, &outlen, NULL((void *)0));
230 if (err)
231 goto done;
232 if (outlen == 0)
233 break;
234 totlen += outlen;
235 if (memchr(zb.outbuf, '\0', outlen) == NULL((void *)0)) {
236 char *newbuf;
237 nbuf++;
238 newbuf = recallocarray(buf, nbuf - 1, nbuf, zbsize);
239 if (newbuf == NULL((void *)0)) {
240 err = got_error_from_errno("recallocarray");
241 goto done;
242 }
243 buf = newbuf;
244 zb.outbuf = newbuf + totlen;
245 zb.outlen = (nbuf * zbsize) - totlen;
246 }
247 } while (memchr(zb.outbuf, '\0', outlen) == NULL((void *)0));
248
249 err = got_object_parse_header(obj, buf, totlen);
250done:
251 free(buf);
252 got_inflate_end(&zb);
253 return err;
254}
255
256struct got_commit_object *
257got_object_commit_alloc_partial(void)
258{
259 struct got_commit_object *commit;
260
261 commit = calloc(1, sizeof(*commit));
262 if (commit == NULL((void *)0))
263 return NULL((void *)0);
264 commit->tree_id = malloc(sizeof(*commit->tree_id));
265 if (commit->tree_id == NULL((void *)0)) {
266 free(commit);
267 return NULL((void *)0);
268 }
269
270 SIMPLEQ_INIT(&commit->parent_ids)do { (&commit->parent_ids)->sqh_first = ((void *)0)
; (&commit->parent_ids)->sqh_last = &(&commit
->parent_ids)->sqh_first; } while (0)
;
271
272 return commit;
273}
274
275const struct got_error *
276got_object_commit_add_parent(struct got_commit_object *commit,
277 const char *id_str)
278{
279 const struct got_error *err = NULL((void *)0);
280 struct got_object_qid *qid;
281
282 err = got_object_qid_alloc_partial(&qid);
13
Calling 'got_object_qid_alloc_partial'
20
Returning from 'got_object_qid_alloc_partial'
283 if (err)
21
Assuming 'err' is null
22
Taking false branch
284 return err;
285
286 if (!got_parse_sha1_digest(qid->id->sha1, id_str)) {
23
Access to field 'id' results in a dereference of a null pointer (loaded from variable 'qid')
287 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
288 got_object_qid_free(qid);
289 return err;
290 }
291
292 SIMPLEQ_INSERT_TAIL(&commit->parent_ids, qid, entry)do { (qid)->entry.sqe_next = ((void *)0); *(&commit->
parent_ids)->sqh_last = (qid); (&commit->parent_ids
)->sqh_last = &(qid)->entry.sqe_next; } while (0)
;
293 commit->nparents++;
294
295 return NULL((void *)0);
296}
297
298static const struct got_error *
299parse_gmtoff(time_t *gmtoff, const char *tzstr)
300{
301 int sign = 1;
302 const char *p = tzstr;
303 time_t h, m;
304
305 *gmtoff = 0;
306
307 if (*p == '-')
308 sign = -1;
309 else if (*p != '+')
310 return got_error(GOT_ERR_BAD_OBJ_DATA12);
311 p++;
312 if (!isdigit(*p) && !isdigit(*(p + 1)))
313 return got_error(GOT_ERR_BAD_OBJ_DATA12);
314 h = (((*p - '0') * 10) + (*(p + 1) - '0'));
315
316 p += 2;
317 if (!isdigit(*p) && !isdigit(*(p + 1)))
318 return got_error(GOT_ERR_BAD_OBJ_DATA12);
319 m = ((*p - '0') * 10) + (*(p + 1) - '0');
320
321 *gmtoff = (h * 60 * 60 + m * 60) * sign;
322 return NULL((void *)0);
323}
324
325static const struct got_error *
326parse_commit_time(time_t *time, time_t *gmtoff, char *committer)
327{
328 const struct got_error *err = NULL((void *)0);
329 const char *errstr;
330 char *space, *tzstr;
331
332 /* Parse and strip off trailing timezone indicator string. */
333 space = strrchr(committer, ' ');
334 if (space == NULL((void *)0))
335 return got_error(GOT_ERR_BAD_OBJ_DATA12);
336 tzstr = strdup(space + 1);
337 if (tzstr == NULL((void *)0))
338 return got_error_from_errno("strdup");
339 err = parse_gmtoff(gmtoff, tzstr);
340 free(tzstr);
341 if (err) {
342 if (err->code != GOT_ERR_BAD_OBJ_DATA12)
343 return err;
344 /* Old versions of Git omitted the timestamp. */
345 *time = 0;
346 *gmtoff = 0;
347 return NULL((void *)0);
348 }
349 *space = '\0';
350
351 /* Timestamp is separated from committer name + email by space. */
352 space = strrchr(committer, ' ');
353 if (space == NULL((void *)0))
354 return got_error(GOT_ERR_BAD_OBJ_DATA12);
355
356 /* Timestamp parsed here is expressed as UNIX timestamp (UTC). */
357 *time = strtonum(space + 1, 0, INT64_MAX0x7fffffffffffffffLL, &errstr);
358 if (errstr)
359 return got_error(GOT_ERR_BAD_OBJ_DATA12);
360
361 /* Strip off parsed time information, leaving just author and email. */
362 *space = '\0';
363
364 return NULL((void *)0);
365}
366
367void
368got_object_commit_close(struct got_commit_object *commit)
369{
370 if (commit->refcnt > 0) {
371 commit->refcnt--;
372 if (commit->refcnt > 0)
373 return;
374 }
375
376 got_object_id_queue_free(&commit->parent_ids);
377 free(commit->tree_id);
378 free(commit->author);
379 free(commit->committer);
380 free(commit->logmsg);
381 free(commit);
382}
383
384struct got_object_id *
385got_object_commit_get_tree_id(struct got_commit_object *commit)
386{
387 return commit->tree_id;
388}
389
390int
391got_object_commit_get_nparents(struct got_commit_object *commit)
392{
393 return commit->nparents;
394}
395
396const struct got_object_id_queue *
397got_object_commit_get_parent_ids(struct got_commit_object *commit)
398{
399 return &commit->parent_ids;
400}
401
402const char *
403got_object_commit_get_author(struct got_commit_object *commit)
404{
405 return commit->author;
406}
407
408time_t
409got_object_commit_get_author_time(struct got_commit_object *commit)
410{
411 return commit->author_time;
412}
413
414time_t got_object_commit_get_author_gmtoff(struct got_commit_object *commit)
415{
416 return commit->author_gmtoff;
417}
418
419const char *
420got_object_commit_get_committer(struct got_commit_object *commit)
421{
422 return commit->committer;
423}
424
425time_t
426got_object_commit_get_committer_time(struct got_commit_object *commit)
427{
428 return commit->committer_time;
429}
430
431time_t
432got_object_commit_get_committer_gmtoff(struct got_commit_object *commit)
433{
434 return commit->committer_gmtoff;
435}
436
437const struct got_error *
438got_object_commit_get_logmsg(char **logmsg, struct got_commit_object *commit)
439{
440 const struct got_error *err = NULL((void *)0);
441 char *msg0, *msg, *line, *s;
442 size_t len;
443 int headers = 1;
444
445 *logmsg = NULL((void *)0);
446
447 msg0 = strdup(commit->logmsg);
448 if (msg0 == NULL((void *)0))
449 return got_error_from_errno("strdup");
450
451 /* Copy log message line by line to strip out unusual headers... */
452 msg = msg0;
453 do {
454 if ((line = strsep(&msg, "\n")) == NULL((void *)0))
455 break;
456
457 if (headers == 1) {
458 if (line[0] != '\0' &&
459 strncmp(line, GOT_COMMIT_LABEL_TREE"tree ",
460 strlen(GOT_COMMIT_LABEL_TREE"tree ")) != 0 &&
461 strncmp(line, GOT_COMMIT_LABEL_AUTHOR"author ",
462 strlen(GOT_COMMIT_LABEL_AUTHOR"author ")) != 0 &&
463 strncmp(line, GOT_COMMIT_LABEL_PARENT"parent ",
464 strlen(GOT_COMMIT_LABEL_PARENT"parent ")) != 0 &&
465 strncmp(line, GOT_COMMIT_LABEL_COMMITTER"committer ",
466 strlen(GOT_COMMIT_LABEL_COMMITTER"committer ")) != 0)
467 continue;
468
469 if (line[0] == '\0')
470 headers = 0;
471 }
472
473 if (asprintf(&s, "%s%s\n",
474 *logmsg ? *logmsg : "", line) == -1) {
475 err = got_error_from_errno("asprintf");
476 goto done;
477 }
478 free(*logmsg);
479 *logmsg = s;
480
481 } while (line);
482
483 if (*logmsg == NULL((void *)0)) {
484 /* log message does not contain \n */
485 *logmsg = strdup(commit->logmsg);
486 if (*logmsg == NULL((void *)0)) {
487 err = got_error_from_errno("strdup");
488 goto done;
489 }
490 }
491
492 /* Trim redundant trailing whitespace. */
493 len = strlen(*logmsg);
494 while (len > 1 && isspace((unsigned char)(*logmsg)[len - 2]) &&
495 isspace((unsigned char)(*logmsg)[len - 1])) {
496 (*logmsg)[len - 1] = '\0';
497 len--;
498 }
499done:
500 free(msg0);
501 if (err) {
502 free(*logmsg);
503 *logmsg = NULL((void *)0);
504 }
505 return err;
506}
507
508const char *
509got_object_commit_get_logmsg_raw(struct got_commit_object *commit)
510{
511 return commit->logmsg;
512}
513
514const struct got_error *
515got_object_parse_commit(struct got_commit_object **commit, char *buf,
516 size_t len)
517{
518 const struct got_error *err = NULL((void *)0);
519 char *s = buf;
520 size_t label_len;
521 ssize_t remain = (ssize_t)len;
522
523 if (remain == 0)
1
Assuming 'remain' is not equal to 0
2
Taking false branch
524 return got_error(GOT_ERR_BAD_OBJ_DATA12);
525
526 *commit = got_object_commit_alloc_partial();
527 if (*commit == NULL((void *)0))
3
Taking false branch
528 return got_error_from_errno("got_object_commit_alloc_partial");
529
530 label_len = strlen(GOT_COMMIT_LABEL_TREE"tree ");
531 if (strncmp(s, GOT_COMMIT_LABEL_TREE"tree ", label_len) == 0) {
4
Taking true branch
532 remain -= label_len;
533 if (remain < SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1)) {
5
Assuming the condition is false
6
Taking false branch
534 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
535 goto done;
536 }
537 s += label_len;
538 if (!got_parse_sha1_digest((*commit)->tree_id->sha1, s)) {
7
Assuming the condition is false
8
Taking false branch
539 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
540 goto done;
541 }
542 remain -= SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1);
543 s += SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1);
544 } else {
545 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
546 goto done;
547 }
548
549 label_len = strlen(GOT_COMMIT_LABEL_PARENT"parent ");
550 while (strncmp(s, GOT_COMMIT_LABEL_PARENT"parent ", label_len) == 0) {
9
Loop condition is true. Entering loop body
551 remain -= label_len;
552 if (remain < SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1)) {
10
Assuming the condition is false
11
Taking false branch
553 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
554 goto done;
555 }
556 s += label_len;
557 err = got_object_commit_add_parent(*commit, s);
12
Calling 'got_object_commit_add_parent'
558 if (err)
559 goto done;
560
561 remain -= SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1);
562 s += SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1);
563 }
564
565 label_len = strlen(GOT_COMMIT_LABEL_AUTHOR"author ");
566 if (strncmp(s, GOT_COMMIT_LABEL_AUTHOR"author ", label_len) == 0) {
567 char *p;
568 size_t slen;
569
570 remain -= label_len;
571 if (remain <= 0) {
572 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
573 goto done;
574 }
575 s += label_len;
576 p = memchr(s, '\n', remain);
577 if (p == NULL((void *)0)) {
578 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
579 goto done;
580 }
581 *p = '\0';
582 slen = strlen(s);
583 err = parse_commit_time(&(*commit)->author_time,
584 &(*commit)->author_gmtoff, s);
585 if (err)
586 goto done;
587 (*commit)->author = strdup(s);
588 if ((*commit)->author == NULL((void *)0)) {
589 err = got_error_from_errno("strdup");
590 goto done;
591 }
592 s += slen + 1;
593 remain -= slen + 1;
594 }
595
596 label_len = strlen(GOT_COMMIT_LABEL_COMMITTER"committer ");
597 if (strncmp(s, GOT_COMMIT_LABEL_COMMITTER"committer ", label_len) == 0) {
598 char *p;
599 size_t slen;
600
601 remain -= label_len;
602 if (remain <= 0) {
603 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
604 goto done;
605 }
606 s += label_len;
607 p = memchr(s, '\n', remain);
608 if (p == NULL((void *)0)) {
609 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
610 goto done;
611 }
612 *p = '\0';
613 slen = strlen(s);
614 err = parse_commit_time(&(*commit)->committer_time,
615 &(*commit)->committer_gmtoff, s);
616 if (err)
617 goto done;
618 (*commit)->committer = strdup(s);
619 if ((*commit)->committer == NULL((void *)0)) {
620 err = got_error_from_errno("strdup");
621 goto done;
622 }
623 s += slen + 1;
624 remain -= slen + 1;
625 }
626
627 (*commit)->logmsg = strndup(s, remain);
628 if ((*commit)->logmsg == NULL((void *)0)) {
629 err = got_error_from_errno("strndup");
630 goto done;
631 }
632done:
633 if (err) {
634 got_object_commit_close(*commit);
635 *commit = NULL((void *)0);
636 }
637 return err;
638}
639
640void
641got_object_tree_close(struct got_tree_object *tree)
642{
643 if (tree->refcnt > 0) {
644 tree->refcnt--;
645 if (tree->refcnt > 0)
646 return;
647 }
648
649 free(tree->entries);
650 free(tree);
651}
652
653static const struct got_error *
654parse_tree_entry(struct got_parsed_tree_entry **pte, const char **name,
655 size_t *elen, char *buf,
656 size_t maxlen)
657{
658 char *p, *space;
659 const struct got_error *err = NULL((void *)0);
660
661 *name = NULL((void *)0);
662 *elen = 0;
663
664 *pte = malloc(sizeof(**pte));
665 if (*pte == NULL((void *)0))
666 return got_error_from_errno("malloc");
667
668 *elen = strnlen(buf, maxlen) + 1;
669 if (*elen > maxlen) {
670 free(*pte);
671 *pte = NULL((void *)0);
672 return got_error(GOT_ERR_BAD_OBJ_DATA12);
673 }
674
675 space = memchr(buf, ' ', *elen);
676 if (space == NULL((void *)0) || space <= buf) {
677 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
678 free(*pte);
679 *pte = NULL((void *)0);
680 return err;
681 }
682 (*pte)->mode = 0;
683 p = buf;
684 while (p < space) {
685 if (*p < '0' && *p > '7') {
686 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
687 goto done;
688 }
689 (*pte)->mode <<= 3;
690 (*pte)->mode |= *p - '0';
691 p++;
692 }
693
694 if (*elen > maxlen || maxlen - *elen < SHA1_DIGEST_LENGTH20) {
695 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
696 goto done;
697 }
698 *name = space + 1;
699 buf += *elen;
700 (*pte)->id = buf;
701 *elen += SHA1_DIGEST_LENGTH20;
702done:
703 if (err) {
704 free(*pte);
705 *pte = NULL((void *)0);
706 }
707 return err;
708}
709
710const struct got_error *
711got_object_parse_tree(struct got_pathlist_head *entries, int *nentries,
712 uint8_t *buf, size_t len)
713{
714 const struct got_error *err = NULL((void *)0);
715 size_t remain = len;
716
717 *nentries = 0;
718 if (remain == 0)
719 return NULL((void *)0); /* tree is empty */
720
721 while (remain > 0) {
722 struct got_parsed_tree_entry *pte;
723 struct got_pathlist_entry *new = NULL((void *)0);
724 const char *name;
725 size_t elen;
726
727 err = parse_tree_entry(&pte, &name, &elen, buf, remain);
728 if (err)
729 goto done;
730 err = got_pathlist_insert(&new, entries, name, pte);
731 if (err)
732 goto done;
733 if (new == NULL((void *)0)) {
734 err = got_error(GOT_ERR_TREE_DUP_ENTRY58);
735 goto done;
736 }
737 buf += elen;
738 remain -= elen;
739 (*nentries)++;
740 }
741
742 if (remain != 0) {
743 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
744 goto done;
745 }
746done:
747 if (err) {
748 got_object_parsed_tree_entries_free(entries);
749 *nentries = 0;
750 }
751 return err;
752}
753
754void
755got_object_parsed_tree_entries_free(struct got_pathlist_head *entries)
756{
757 struct got_pathlist_entry *pe;
758
759 TAILQ_FOREACH(pe, entries, entry)for((pe) = ((entries)->tqh_first); (pe) != ((void *)0); (pe
) = ((pe)->entry.tqe_next))
{
760 struct got_parsed_tree_entry *pte = pe->data;
761 free(pte);
762 }
763 got_pathlist_free(entries);
764}
765
766void
767got_object_tag_close(struct got_tag_object *tag)
768{
769 if (tag->refcnt > 0) {
770 tag->refcnt--;
771 if (tag->refcnt > 0)
772 return;
773 }
774
775 free(tag->tag);
776 free(tag->tagger);
777 free(tag->tagmsg);
778 free(tag);
779}
780
781const struct got_error *
782got_object_parse_tag(struct got_tag_object **tag, uint8_t *buf, size_t len)
783{
784 const struct got_error *err = NULL((void *)0);
785 size_t remain = len;
786 char *s = buf;
787 size_t label_len;
788
789 if (remain == 0)
790 return got_error(GOT_ERR_BAD_OBJ_DATA12);
791
792 *tag = calloc(1, sizeof(**tag));
793 if (*tag == NULL((void *)0))
794 return got_error_from_errno("calloc");
795
796 label_len = strlen(GOT_TAG_LABEL_OBJECT"object ");
797 if (strncmp(s, GOT_TAG_LABEL_OBJECT"object ", label_len) == 0) {
798 remain -= label_len;
799 if (remain < SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1)) {
800 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
801 goto done;
802 }
803 s += label_len;
804 if (!got_parse_sha1_digest((*tag)->id.sha1, s)) {
805 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
806 goto done;
807 }
808 remain -= SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1);
809 s += SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1);
810 } else {
811 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
812 goto done;
813 }
814
815 if (remain <= 0) {
816 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
817 goto done;
818 }
819
820 label_len = strlen(GOT_TAG_LABEL_TYPE"type ");
821 if (strncmp(s, GOT_TAG_LABEL_TYPE"type ", label_len) == 0) {
822 remain -= label_len;
823 if (remain <= 0) {
824 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
825 goto done;
826 }
827 s += label_len;
828 if (strncmp(s, GOT_OBJ_LABEL_COMMIT"commit",
829 strlen(GOT_OBJ_LABEL_COMMIT"commit")) == 0) {
830 (*tag)->obj_type = GOT_OBJ_TYPE_COMMIT1;
831 label_len = strlen(GOT_OBJ_LABEL_COMMIT"commit");
832 s += label_len;
833 remain -= label_len;
834 } else if (strncmp(s, GOT_OBJ_LABEL_TREE"tree",
835 strlen(GOT_OBJ_LABEL_TREE"tree")) == 0) {
836 (*tag)->obj_type = GOT_OBJ_TYPE_TREE2;
837 label_len = strlen(GOT_OBJ_LABEL_TREE"tree");
838 s += label_len;
839 remain -= label_len;
840 } else if (strncmp(s, GOT_OBJ_LABEL_BLOB"blob",
841 strlen(GOT_OBJ_LABEL_BLOB"blob")) == 0) {
842 (*tag)->obj_type = GOT_OBJ_TYPE_BLOB3;
843 label_len = strlen(GOT_OBJ_LABEL_BLOB"blob");
844 s += label_len;
845 remain -= label_len;
846 } else if (strncmp(s, GOT_OBJ_LABEL_TAG"tag",
847 strlen(GOT_OBJ_LABEL_TAG"tag")) == 0) {
848 (*tag)->obj_type = GOT_OBJ_TYPE_TAG4;
849 label_len = strlen(GOT_OBJ_LABEL_TAG"tag");
850 s += label_len;
851 remain -= label_len;
852 } else {
853 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
854 goto done;
855 }
856
857 if (remain <= 0 || *s != '\n') {
858 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
859 goto done;
860 }
861 s++;
862 remain--;
863 if (remain <= 0) {
864 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
865 goto done;
866 }
867 } else {
868 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
869 goto done;
870 }
871
872 label_len = strlen(GOT_TAG_LABEL_TAG"tag ");
873 if (strncmp(s, GOT_TAG_LABEL_TAG"tag ", label_len) == 0) {
874 char *p;
875 size_t slen;
876 remain -= label_len;
877 if (remain <= 0) {
878 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
879 goto done;
880 }
881 s += label_len;
882 p = memchr(s, '\n', remain);
883 if (p == NULL((void *)0)) {
884 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
885 goto done;
886 }
887 *p = '\0';
888 slen = strlen(s);
889 (*tag)->tag = strndup(s, slen);
890 if ((*tag)->tag == NULL((void *)0)) {
891 err = got_error_from_errno("strndup");
892 goto done;
893 }
894 s += slen + 1;
895 remain -= slen + 1;
896 if (remain <= 0) {
897 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
898 goto done;
899 }
900 } else {
901 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
902 goto done;
903 }
904
905 label_len = strlen(GOT_TAG_LABEL_TAGGER"tagger ");
906 if (strncmp(s, GOT_TAG_LABEL_TAGGER"tagger ", label_len) == 0) {
907 char *p;
908 size_t slen;
909
910 remain -= label_len;
911 if (remain <= 0) {
912 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
913 goto done;
914 }
915 s += label_len;
916 p = memchr(s, '\n', remain);
917 if (p == NULL((void *)0)) {
918 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
919 goto done;
920 }
921 *p = '\0';
922 slen = strlen(s);
923 err = parse_commit_time(&(*tag)->tagger_time,
924 &(*tag)->tagger_gmtoff, s);
925 if (err)
926 goto done;
927 (*tag)->tagger = strdup(s);
928 if ((*tag)->tagger == NULL((void *)0)) {
929 err = got_error_from_errno("strdup");
930 goto done;
931 }
932 s += slen + 1;
933 remain -= slen + 1;
934 if (remain < 0) {
935 err = got_error(GOT_ERR_BAD_OBJ_DATA12);
936 goto done;
937 }
938 } else {
939 /* Some old tags in the Linux git repo have no tagger. */
940 (*tag)->tagger = strdup("");
941 if ((*tag)->tagger == NULL((void *)0)) {
942 err = got_error_from_errno("strdup");
943 goto done;
944 }
945 }
946
947 (*tag)->tagmsg = strndup(s, remain);
948 if ((*tag)->tagmsg == NULL((void *)0)) {
949 err = got_error_from_errno("strndup");
950 goto done;
951 }
952done:
953 if (err) {
954 got_object_tag_close(*tag);
955 *tag = NULL((void *)0);
956 }
957 return err;
958}
959
960const struct got_error *
961got_read_file_to_mem(uint8_t **outbuf, size_t *outlen, FILE *f)
962{
963 const struct got_error *err = NULL((void *)0);
964 static const size_t blocksize = 512;
965 size_t n, total, remain;
966 uint8_t *buf;
967
968 *outbuf = NULL((void *)0);
969 *outlen = 0;
970
971 buf = malloc(blocksize);
972 if (buf == NULL((void *)0))
973 return got_error_from_errno("malloc");
974
975 remain = blocksize;
976 total = 0;
977 for (;;) {
978 if (remain == 0) {
979 uint8_t *newbuf;
980 newbuf = reallocarray(buf, 1, total + blocksize);
981 if (newbuf == NULL((void *)0)) {
982 err = got_error_from_errno("reallocarray");
983 goto done;
984 }
985 buf = newbuf;
986 remain += blocksize;
987 }
988 n = fread(buf + total, 1, remain, f);
989 if (n == 0) {
990 if (ferror(f)(!__isthreaded ? (((f)->_flags & 0x0040) != 0) : (ferror
)(f))
) {
991 err = got_ferror(f, GOT_ERR_IO6);
992 goto done;
993 }
994 break; /* EOF */
995 }
996 remain -= n;
997 total += n;
998 };
999
1000done:
1001 if (err == NULL((void *)0)) {
1002 *outbuf = buf;
1003 *outlen = total;
1004 } else
1005 free(buf);
1006 return err;
1007}