2 * Copyright (c) 2018 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.
18 #include <sys/queue.h>
29 #include "got_error.h"
30 #include "got_object.h"
31 #include "got_repository.h"
39 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
43 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
46 #define GOT_OBJ_TAG_COMMIT "commit"
47 #define GOT_OBJ_TAG_TREE "tree"
48 #define GOT_OBJ_TAG_BLOB "blob"
50 #define GOT_COMMIT_TAG_TREE "tree "
51 #define GOT_COMMIT_TAG_PARENT "parent "
52 #define GOT_COMMIT_TAG_AUTHOR "author "
53 #define GOT_COMMIT_TAG_COMMITTER "committer "
55 const struct got_error *
56 got_object_id_str(char **outbuf, struct got_object_id *id)
58 static const size_t len = SHA1_DIGEST_STRING_LENGTH;
60 *outbuf = calloc(1, len);
62 return got_error(GOT_ERR_NO_MEM);
64 if (got_sha1_digest_to_str(id->sha1, *outbuf, len) == NULL) {
67 return got_error(GOT_ERR_BAD_OBJ_ID_STR);
74 got_object_id_cmp(struct got_object_id *id1, struct got_object_id *id2)
76 return memcmp(id1->sha1, id2->sha1, SHA1_DIGEST_LENGTH);
80 got_object_get_type(struct got_object *obj)
83 case GOT_OBJ_TYPE_COMMIT:
84 case GOT_OBJ_TYPE_TREE:
85 case GOT_OBJ_TYPE_BLOB:
86 case GOT_OBJ_TYPE_TAG:
97 static const struct got_error *
98 parse_object_header(struct got_object **obj, char *buf, size_t len)
100 const char *obj_tags[] = {
105 const int obj_types[] = {
111 size_t size = 0, hdrlen = 0;
113 char *p = strchr(buf, '\0');
116 return got_error(GOT_ERR_BAD_OBJ_HDR);
118 hdrlen = strlen(buf) + 1 /* '\0' */;
120 for (i = 0; i < nitems(obj_tags); i++) {
121 const char *tag = obj_tags[i];
122 size_t tlen = strlen(tag);
125 if (strncmp(buf, tag, tlen) != 0)
130 return got_error(GOT_ERR_BAD_OBJ_HDR);
131 size = strtonum(buf + tlen, 0, LONG_MAX, &errstr);
133 return got_error(GOT_ERR_BAD_OBJ_HDR);
138 return got_error(GOT_ERR_BAD_OBJ_HDR);
140 *obj = calloc(1, sizeof(**obj));
142 return got_error(GOT_ERR_NO_MEM);
144 (*obj)->hdrlen = hdrlen;
149 static const struct got_error *
150 read_object_header(struct got_object **obj, struct got_repository *repo,
153 const struct got_error *err;
154 struct got_zstream_buf zb;
157 const size_t zbsize = 64;
158 size_t outlen, totlen;
161 buf = calloc(zbsize, sizeof(char));
163 return got_error(GOT_ERR_NO_MEM);
165 err = got_inflate_init(&zb, zbsize);
172 err = got_inflate_read(&zb, f, &outlen);
175 if (strchr(zb.outbuf, '\0') == NULL) {
176 buf = recallocarray(buf, 1 + i, 2 + i, zbsize);
178 err = got_error(GOT_ERR_NO_MEM);
182 memcpy(buf + totlen, zb.outbuf, outlen);
185 } while (strchr(zb.outbuf, '\0') == NULL);
187 err = parse_object_header(obj, buf, totlen);
189 got_inflate_end(&zb);
193 static const struct got_error *
194 object_path(char **path, struct got_object_id *id, struct got_repository *repo)
196 const struct got_error *err = NULL;
198 char *path_objects = got_repo_get_path_objects(repo);
200 if (path_objects == NULL)
201 return got_error(GOT_ERR_NO_MEM);
203 err = got_object_id_str(&hex, id);
207 if (asprintf(path, "%s/%.2x/%s", path_objects,
208 id->sha1[0], hex + 2) == -1)
209 err = got_error(GOT_ERR_NO_MEM);
216 static const struct got_error *
217 open_loose_object(FILE **f, struct got_object *obj, struct got_repository *repo)
219 const struct got_error *err = NULL;
222 err = object_path(&path, &obj->id, repo);
225 *f = fopen(path, "rb");
227 err = got_error_from_errno();
235 const struct got_error *
236 got_object_open(struct got_object **obj, struct got_repository *repo,
237 struct got_object_id *id)
239 const struct got_error *err = NULL;
243 err = object_path(&path, id, repo);
247 f = fopen(path, "rb");
249 if (errno != ENOENT) {
250 err = got_error_from_errno();
253 err = got_packfile_open_object(obj, id, repo);
257 err = got_error(GOT_ERR_NO_OBJ);
259 err = read_object_header(obj, repo, f);
262 memcpy((*obj)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH);
272 const struct got_error *
273 got_object_open_by_id_str(struct got_object **obj, struct got_repository *repo,
276 struct got_object_id id;
278 if (!got_parse_sha1_digest(id.sha1, id_str))
279 return got_error(GOT_ERR_BAD_OBJ_ID_STR);
281 return got_object_open(obj, repo, &id);
285 got_object_close(struct got_object *obj)
287 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
288 struct got_delta *delta;
289 while (!SIMPLEQ_EMPTY(&obj->deltas.entries)) {
290 delta = SIMPLEQ_FIRST(&obj->deltas.entries);
291 SIMPLEQ_REMOVE_HEAD(&obj->deltas.entries, entry);
292 got_delta_close(delta);
295 if (obj->flags & GOT_OBJ_FLAG_PACKED)
296 free(obj->path_packfile);
301 commit_object_valid(struct got_commit_object *commit)
310 for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
311 if (commit->tree_id->sha1[i] == 0)
314 if (n == SHA1_DIGEST_LENGTH)
320 static const struct got_error *
321 parse_commit_object(struct got_commit_object **commit, char *buf, size_t len)
323 const struct got_error *err = NULL;
326 ssize_t remain = (ssize_t)len;
328 *commit = calloc(1, sizeof(**commit));
330 return got_error(GOT_ERR_NO_MEM);
331 (*commit)->tree_id = calloc(1, sizeof(*(*commit)->tree_id));
332 if ((*commit)->tree_id == NULL) {
335 return got_error(GOT_ERR_NO_MEM);
338 SIMPLEQ_INIT(&(*commit)->parent_ids);
340 tlen = strlen(GOT_COMMIT_TAG_TREE);
341 if (strncmp(s, GOT_COMMIT_TAG_TREE, tlen) == 0) {
343 if (remain < SHA1_DIGEST_STRING_LENGTH) {
344 err = got_error(GOT_ERR_BAD_OBJ_DATA);
348 if (!got_parse_sha1_digest((*commit)->tree_id->sha1, s)) {
349 err = got_error(GOT_ERR_BAD_OBJ_DATA);
352 remain -= SHA1_DIGEST_STRING_LENGTH;
353 s += SHA1_DIGEST_STRING_LENGTH;
355 err = got_error(GOT_ERR_BAD_OBJ_DATA);
359 tlen = strlen(GOT_COMMIT_TAG_PARENT);
360 while (strncmp(s, GOT_COMMIT_TAG_PARENT, tlen) == 0) {
361 struct got_parent_id *pid;
364 if (remain < SHA1_DIGEST_STRING_LENGTH) {
365 err = got_error(GOT_ERR_BAD_OBJ_DATA);
369 pid = calloc(1, sizeof(*pid));
371 err = got_error(GOT_ERR_NO_MEM);
374 pid->id = calloc(1, sizeof(*pid->id));
375 if (pid->id == NULL) {
377 err = got_error(GOT_ERR_NO_MEM);
381 if (!got_parse_sha1_digest(pid->id->sha1, s)) {
382 err = got_error(GOT_ERR_BAD_OBJ_DATA);
387 SIMPLEQ_INSERT_TAIL(&(*commit)->parent_ids, pid, entry);
388 (*commit)->nparents++;
390 remain -= SHA1_DIGEST_STRING_LENGTH;
391 s += SHA1_DIGEST_STRING_LENGTH;
394 tlen = strlen(GOT_COMMIT_TAG_AUTHOR);
395 if (strncmp(s, GOT_COMMIT_TAG_AUTHOR, tlen) == 0) {
400 err = got_error(GOT_ERR_BAD_OBJ_DATA);
406 err = got_error(GOT_ERR_BAD_OBJ_DATA);
410 (*commit)->author = strdup(s);
411 if ((*commit)->author == NULL) {
412 err = got_error(GOT_ERR_NO_MEM);
415 s += strlen((*commit)->author) + 1;
416 remain -= strlen((*commit)->author) + 1;
419 tlen = strlen(GOT_COMMIT_TAG_COMMITTER);
420 if (strncmp(s, GOT_COMMIT_TAG_COMMITTER, tlen) == 0) {
425 err = got_error(GOT_ERR_BAD_OBJ_DATA);
431 err = got_error(GOT_ERR_BAD_OBJ_DATA);
435 (*commit)->committer = strdup(s);
436 if ((*commit)->committer == NULL) {
437 err = got_error(GOT_ERR_NO_MEM);
440 s += strlen((*commit)->committer) + 1;
441 remain -= strlen((*commit)->committer) + 1;
444 (*commit)->logmsg = strndup(s, remain);
445 if ((*commit)->logmsg == NULL) {
446 err = got_error(GOT_ERR_NO_MEM);
451 got_object_commit_close(*commit);
458 tree_entry_close(struct got_tree_entry *te)
465 static const struct got_error *
466 parse_tree_entry(struct got_tree_entry **te, size_t *elen, char *buf,
469 char *p = buf, *space;
470 const struct got_error *err = NULL;
471 char hex[SHA1_DIGEST_STRING_LENGTH];
473 *te = calloc(1, sizeof(**te));
475 return got_error(GOT_ERR_NO_MEM);
477 (*te)->id = calloc(1, sizeof(*(*te)->id));
478 if ((*te)->id == NULL) {
481 return got_error(GOT_ERR_NO_MEM);
484 *elen = strlen(buf) + 1;
485 if (*elen > maxlen) {
488 return got_error(GOT_ERR_BAD_OBJ_DATA);
491 space = strchr(buf, ' ');
495 return got_error(GOT_ERR_BAD_OBJ_DATA);
498 if (*p < '0' && *p > '7') {
499 err = got_error(GOT_ERR_BAD_OBJ_DATA);
503 (*te)->mode |= *p - '0';
507 (*te)->name = strdup(space + 1);
508 if (*elen > maxlen || maxlen - *elen < SHA1_DIGEST_LENGTH) {
509 err = got_error(GOT_ERR_BAD_OBJ_DATA);
512 buf += strlen(buf) + 1;
513 memcpy((*te)->id->sha1, buf, SHA1_DIGEST_LENGTH);
514 *elen += SHA1_DIGEST_LENGTH;
517 tree_entry_close(*te);
523 static const struct got_error *
524 parse_tree_object(struct got_tree_object **tree, struct got_repository *repo,
525 char *buf, size_t len)
527 const struct got_error *err;
531 *tree = calloc(1, sizeof(**tree));
533 return got_error(GOT_ERR_NO_MEM);
535 SIMPLEQ_INIT(&(*tree)->entries);
538 struct got_tree_entry *te;
541 err = parse_tree_entry(&te, &elen, buf, remain);
545 SIMPLEQ_INSERT_TAIL(&(*tree)->entries, te, entry);
551 got_object_tree_close(*tree);
552 return got_error(GOT_ERR_BAD_OBJ_DATA);
558 static const struct got_error *
559 read_to_mem(uint8_t **outbuf, size_t *outlen, FILE *f)
561 const struct got_error *err = NULL;
562 static const size_t blocksize = 512;
563 size_t n, total, remain;
569 buf = calloc(1, blocksize);
571 return got_error(GOT_ERR_NO_MEM);
578 newbuf = reallocarray(buf, 1, total + blocksize);
579 if (newbuf == NULL) {
580 err = got_error(GOT_ERR_NO_MEM);
586 n = fread(buf, 1, remain, f);
589 err = got_ferror(f, GOT_ERR_IO);
607 static const struct got_error *
608 read_commit_object(struct got_commit_object **commit,
609 struct got_repository *repo, struct got_object *obj, FILE *f)
611 const struct got_error *err = NULL;
616 if (obj->flags & GOT_OBJ_FLAG_PACKED)
617 err = read_to_mem(&p, &len, f);
619 err = got_inflate_to_mem(&p, &len, f);
623 if (len < obj->hdrlen + obj->size) {
624 err = got_error(GOT_ERR_BAD_OBJ_DATA);
628 /* Skip object header. */
630 err = parse_commit_object(commit, p + obj->hdrlen, len);
636 const struct got_error *
637 got_object_commit_open(struct got_commit_object **commit,
638 struct got_repository *repo, struct got_object *obj)
640 const struct got_error *err = NULL;
643 if (obj->type != GOT_OBJ_TYPE_COMMIT)
644 return got_error(GOT_ERR_OBJ_TYPE);
646 if (obj->flags & GOT_OBJ_FLAG_PACKED)
647 err = got_packfile_extract_object(&f, obj, repo);
649 err = open_loose_object(&f, obj, repo);
653 err = read_commit_object(commit, repo, obj, f);
659 got_object_commit_close(struct got_commit_object *commit)
661 struct got_parent_id *pid;
663 while (!SIMPLEQ_EMPTY(&commit->parent_ids)) {
664 pid = SIMPLEQ_FIRST(&commit->parent_ids);
665 SIMPLEQ_REMOVE_HEAD(&commit->parent_ids, entry);
670 free(commit->tree_id);
671 free(commit->author);
672 free(commit->committer);
673 free(commit->logmsg);
677 static const struct got_error *
678 read_tree_object(struct got_tree_object **tree,
679 struct got_repository *repo, struct got_object *obj, FILE *f)
681 const struct got_error *err = NULL;
686 if (obj->flags & GOT_OBJ_FLAG_PACKED)
687 err = read_to_mem(&p, &len, f);
689 err = got_inflate_to_mem(&p, &len, f);
693 if (len < obj->hdrlen + obj->size) {
694 err = got_error(GOT_ERR_BAD_OBJ_DATA);
698 /* Skip object header. */
700 err = parse_tree_object(tree, repo, p + obj->hdrlen, len);
706 const struct got_error *
707 got_object_tree_open(struct got_tree_object **tree,
708 struct got_repository *repo, struct got_object *obj)
710 const struct got_error *err = NULL;
713 if (obj->type != GOT_OBJ_TYPE_TREE)
714 return got_error(GOT_ERR_OBJ_TYPE);
716 if (obj->flags & GOT_OBJ_FLAG_PACKED)
717 err = got_packfile_extract_object(&f, obj, repo);
719 err = open_loose_object(&f, obj, repo);
723 err = read_tree_object(tree, repo, obj, f);
729 got_object_tree_close(struct got_tree_object *tree)
731 struct got_tree_entry *te;
733 while (!SIMPLEQ_EMPTY(&tree->entries)) {
734 te = SIMPLEQ_FIRST(&tree->entries);
735 SIMPLEQ_REMOVE_HEAD(&tree->entries, entry);
736 tree_entry_close(te);
742 const struct got_error *
743 got_object_blob_open(struct got_blob_object **blob,
744 struct got_repository *repo, struct got_object *obj, size_t blocksize)
746 const struct got_error *err = NULL;
748 if (obj->type != GOT_OBJ_TYPE_BLOB)
749 return got_error(GOT_ERR_OBJ_TYPE);
751 if (blocksize < obj->hdrlen)
752 return got_error(GOT_ERR_NO_SPACE);
754 *blob = calloc(1, sizeof(**blob));
756 return got_error(GOT_ERR_NO_MEM);
758 if (obj->flags & GOT_OBJ_FLAG_PACKED) {
759 (*blob)->read_buf = calloc(1, blocksize);
760 if ((*blob)->read_buf == NULL)
761 return got_error(GOT_ERR_NO_MEM);
762 err = got_packfile_extract_object(&((*blob)->f), obj, repo);
766 err = open_loose_object(&((*blob)->f), obj, repo);
772 err = got_inflate_init(&(*blob)->zb, blocksize);
779 (*blob)->read_buf = (*blob)->zb.outbuf;
780 (*blob)->flags |= GOT_BLOB_F_COMPRESSED;
783 (*blob)->hdrlen = obj->hdrlen;
784 (*blob)->blocksize = blocksize;
785 memcpy(&(*blob)->id.sha1, obj->id.sha1, SHA1_DIGEST_LENGTH);
791 got_object_blob_close(struct got_blob_object *blob)
793 if (blob->flags & GOT_BLOB_F_COMPRESSED)
794 got_inflate_end(&blob->zb);
796 free(blob->read_buf);
802 got_object_blob_id_str(struct got_blob_object *blob, char *buf, size_t size)
804 return got_sha1_digest_to_str(blob->id.sha1, buf, size);
808 got_object_blob_get_hdrlen(struct got_blob_object *blob)
814 got_object_blob_get_read_buf(struct got_blob_object *blob)
816 return blob->read_buf;
819 const struct got_error *
820 got_object_blob_read_block(size_t *outlenp, struct got_blob_object *blob)
824 if (blob->flags & GOT_BLOB_F_COMPRESSED)
825 return got_inflate_read(&blob->zb, blob->f, outlenp);
827 n = fread(blob->read_buf, 1, blob->blocksize, blob->f);
828 if (n == 0 && ferror(blob->f))
829 return got_ferror(blob->f, GOT_ERR_IO);