Blob


1 /*
2 * Copyright (c) 2018 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 */
17 #include <sys/stat.h>
18 #include <sys/queue.h>
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sha1.h>
25 #include <zlib.h>
26 #include <ctype.h>
27 #include <limits.h>
29 #include "got_error.h"
30 #include "got_object.h"
31 #include "got_repository.h"
32 #include "got_sha1.h"
33 #include "delta.h"
34 #include "pack.h"
35 #include "zb.h"
36 #include "object.h"
38 #ifndef MIN
39 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
40 #endif
42 #ifndef nitems
43 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
44 #endif
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)
57 {
58 static const size_t len = SHA1_DIGEST_STRING_LENGTH;
60 *outbuf = calloc(1, len);
61 if (*outbuf == NULL)
62 return got_error(GOT_ERR_NO_MEM);
64 if (got_sha1_digest_to_str(id->sha1, *outbuf, len) == NULL) {
65 free(*outbuf);
66 *outbuf = NULL;
67 return got_error(GOT_ERR_BAD_OBJ_ID_STR);
68 }
70 return NULL;
71 }
73 int
74 got_object_id_cmp(struct got_object_id *id1, struct got_object_id *id2)
75 {
76 return memcmp(id1->sha1, id2->sha1, SHA1_DIGEST_LENGTH);
77 }
79 int
80 got_object_get_type(struct got_object *obj)
81 {
82 switch (obj->type) {
83 case GOT_OBJ_TYPE_COMMIT:
84 case GOT_OBJ_TYPE_TREE:
85 case GOT_OBJ_TYPE_BLOB:
86 case GOT_OBJ_TYPE_TAG:
87 return obj->type;
88 default:
89 abort();
90 break;
91 }
93 /* not reached */
94 return 0;
95 }
97 static const struct got_error *
98 parse_object_header(struct got_object **obj, char *buf, size_t len)
99 {
100 const char *obj_tags[] = {
101 GOT_OBJ_TAG_COMMIT,
102 GOT_OBJ_TAG_TREE,
103 GOT_OBJ_TAG_BLOB
104 };
105 const int obj_types[] = {
106 GOT_OBJ_TYPE_COMMIT,
107 GOT_OBJ_TYPE_TREE,
108 GOT_OBJ_TYPE_BLOB,
109 };
110 int type = 0;
111 size_t size = 0, hdrlen = 0;
112 int i;
113 char *p = strchr(buf, '\0');
115 if (p == NULL)
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);
123 const char *errstr;
125 if (strncmp(buf, tag, tlen) != 0)
126 continue;
128 type = obj_types[i];
129 if (len <= tlen)
130 return got_error(GOT_ERR_BAD_OBJ_HDR);
131 size = strtonum(buf + tlen, 0, LONG_MAX, &errstr);
132 if (errstr != NULL)
133 return got_error(GOT_ERR_BAD_OBJ_HDR);
134 break;
137 if (type == 0)
138 return got_error(GOT_ERR_BAD_OBJ_HDR);
140 *obj = calloc(1, sizeof(**obj));
141 if (*obj == NULL)
142 return got_error(GOT_ERR_NO_MEM);
143 (*obj)->type = type;
144 (*obj)->hdrlen = hdrlen;
145 (*obj)->size = size;
146 return NULL;
149 static const struct got_error *
150 read_object_header(struct got_object **obj, struct got_repository *repo,
151 FILE *f)
153 const struct got_error *err;
154 struct got_zstream_buf zb;
155 char *buf;
156 size_t len;
157 const size_t zbsize = 64;
158 size_t outlen, totlen;
159 int i, ret;
161 buf = calloc(zbsize, sizeof(char));
162 if (buf == NULL)
163 return got_error(GOT_ERR_NO_MEM);
165 err = got_inflate_init(&zb, zbsize);
166 if (err)
167 return err;
169 i = 0;
170 totlen = 0;
171 do {
172 err = got_inflate_read(&zb, f, &outlen);
173 if (err)
174 goto done;
175 if (strchr(zb.outbuf, '\0') == NULL) {
176 buf = recallocarray(buf, 1 + i, 2 + i, zbsize);
177 if (buf == NULL) {
178 err = got_error(GOT_ERR_NO_MEM);
179 goto done;
182 memcpy(buf + totlen, zb.outbuf, outlen);
183 totlen += outlen;
184 i++;
185 } while (strchr(zb.outbuf, '\0') == NULL);
187 err = parse_object_header(obj, buf, totlen);
188 done:
189 got_inflate_end(&zb);
190 return err;
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;
197 char *hex;
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);
204 if (err)
205 return err;
207 if (asprintf(path, "%s/%.2x/%s", path_objects,
208 id->sha1[0], hex + 2) == -1)
209 err = got_error(GOT_ERR_NO_MEM);
211 free(hex);
212 free(path_objects);
213 return err;
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;
220 char *path;
222 err = object_path(&path, &obj->id, repo);
223 if (err)
224 return err;
225 *f = fopen(path, "rb");
226 if (*f == NULL) {
227 err = got_error_from_errno();
228 goto done;
230 done:
231 free(path);
232 return err;
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;
240 char *path;
241 FILE *f;
243 err = object_path(&path, id, repo);
244 if (err)
245 return err;
247 f = fopen(path, "rb");
248 if (f == NULL) {
249 if (errno != ENOENT) {
250 err = got_error_from_errno();
251 goto done;
253 err = got_packfile_open_object(obj, id, repo);
254 if (err)
255 goto done;
256 if (*obj == NULL)
257 err = got_error(GOT_ERR_NO_OBJ);
258 } else {
259 err = read_object_header(obj, repo, f);
260 if (err)
261 goto done;
262 memcpy((*obj)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH);
264 done:
265 free(path);
266 if (err && f)
267 fclose(f);
268 return err;
272 const struct got_error *
273 got_object_open_by_id_str(struct got_object **obj, struct got_repository *repo,
274 const char *id_str)
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);
284 void
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);
297 free(obj);
300 static int
301 commit_object_valid(struct got_commit_object *commit)
303 int i;
304 int n;
306 if (commit == NULL)
307 return 0;
309 n = 0;
310 for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
311 if (commit->tree_id->sha1[i] == 0)
312 n++;
314 if (n == SHA1_DIGEST_LENGTH)
315 return 0;
317 return 1;
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;
324 char *s = buf;
325 size_t tlen;
326 ssize_t remain = (ssize_t)len;
328 *commit = calloc(1, sizeof(**commit));
329 if (*commit == NULL)
330 return got_error(GOT_ERR_NO_MEM);
331 (*commit)->tree_id = calloc(1, sizeof(*(*commit)->tree_id));
332 if ((*commit)->tree_id == NULL) {
333 free(*commit);
334 *commit = 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) {
342 remain -= tlen;
343 if (remain < SHA1_DIGEST_STRING_LENGTH) {
344 err = got_error(GOT_ERR_BAD_OBJ_DATA);
345 goto done;
347 s += tlen;
348 if (!got_parse_sha1_digest((*commit)->tree_id->sha1, s)) {
349 err = got_error(GOT_ERR_BAD_OBJ_DATA);
350 goto done;
352 remain -= SHA1_DIGEST_STRING_LENGTH;
353 s += SHA1_DIGEST_STRING_LENGTH;
354 } else {
355 err = got_error(GOT_ERR_BAD_OBJ_DATA);
356 goto done;
359 tlen = strlen(GOT_COMMIT_TAG_PARENT);
360 while (strncmp(s, GOT_COMMIT_TAG_PARENT, tlen) == 0) {
361 struct got_parent_id *pid;
363 remain -= tlen;
364 if (remain < SHA1_DIGEST_STRING_LENGTH) {
365 err = got_error(GOT_ERR_BAD_OBJ_DATA);
366 goto done;
369 pid = calloc(1, sizeof(*pid));
370 if (pid == NULL) {
371 err = got_error(GOT_ERR_NO_MEM);
372 goto done;
374 pid->id = calloc(1, sizeof(*pid->id));
375 if (pid->id == NULL) {
376 free(pid);
377 err = got_error(GOT_ERR_NO_MEM);
378 goto done;
380 s += tlen;
381 if (!got_parse_sha1_digest(pid->id->sha1, s)) {
382 err = got_error(GOT_ERR_BAD_OBJ_DATA);
383 free(pid->id);
384 free(pid);
385 goto done;
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) {
396 char *p;
398 remain -= tlen;
399 if (remain <= 0) {
400 err = got_error(GOT_ERR_BAD_OBJ_DATA);
401 goto done;
403 s += tlen;
404 p = strchr(s, '\n');
405 if (p == NULL) {
406 err = got_error(GOT_ERR_BAD_OBJ_DATA);
407 goto done;
409 *p = '\0';
410 (*commit)->author = strdup(s);
411 if ((*commit)->author == NULL) {
412 err = got_error(GOT_ERR_NO_MEM);
413 goto done;
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) {
421 char *p;
423 remain -= tlen;
424 if (remain <= 0) {
425 err = got_error(GOT_ERR_BAD_OBJ_DATA);
426 goto done;
428 s += tlen;
429 p = strchr(s, '\n');
430 if (p == NULL) {
431 err = got_error(GOT_ERR_BAD_OBJ_DATA);
432 goto done;
434 *p = '\0';
435 (*commit)->committer = strdup(s);
436 if ((*commit)->committer == NULL) {
437 err = got_error(GOT_ERR_NO_MEM);
438 goto done;
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);
447 goto done;
449 done:
450 if (err) {
451 got_object_commit_close(*commit);
452 *commit = NULL;
454 return err;
457 static void
458 tree_entry_close(struct got_tree_entry *te)
460 free(te->id);
461 free(te->name);
462 free(te);
465 static const struct got_error *
466 parse_tree_entry(struct got_tree_entry **te, size_t *elen, char *buf,
467 size_t maxlen)
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));
474 if (*te == NULL)
475 return got_error(GOT_ERR_NO_MEM);
477 (*te)->id = calloc(1, sizeof(*(*te)->id));
478 if ((*te)->id == NULL) {
479 free(*te);
480 *te = NULL;
481 return got_error(GOT_ERR_NO_MEM);
484 *elen = strlen(buf) + 1;
485 if (*elen > maxlen) {
486 free(*te);
487 *te = NULL;
488 return got_error(GOT_ERR_BAD_OBJ_DATA);
491 space = strchr(buf, ' ');
492 if (space == NULL) {
493 free(*te);
494 *te = NULL;
495 return got_error(GOT_ERR_BAD_OBJ_DATA);
497 while (*p != ' ') {
498 if (*p < '0' && *p > '7') {
499 err = got_error(GOT_ERR_BAD_OBJ_DATA);
500 goto done;
502 (*te)->mode <<= 3;
503 (*te)->mode |= *p - '0';
504 p++;
507 (*te)->name = strdup(space + 1);
508 if (*elen > maxlen || maxlen - *elen < SHA1_DIGEST_LENGTH) {
509 err = got_error(GOT_ERR_BAD_OBJ_DATA);
510 goto done;
512 buf += strlen(buf) + 1;
513 memcpy((*te)->id->sha1, buf, SHA1_DIGEST_LENGTH);
514 *elen += SHA1_DIGEST_LENGTH;
515 done:
516 if (err) {
517 tree_entry_close(*te);
518 *te = NULL;
520 return err;
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;
528 size_t remain = len;
529 int nentries;
531 *tree = calloc(1, sizeof(**tree));
532 if (*tree == NULL)
533 return got_error(GOT_ERR_NO_MEM);
535 SIMPLEQ_INIT(&(*tree)->entries);
537 while (remain > 0) {
538 struct got_tree_entry *te;
539 size_t elen;
541 err = parse_tree_entry(&te, &elen, buf, remain);
542 if (err)
543 return err;
544 (*tree)->nentries++;
545 SIMPLEQ_INSERT_TAIL(&(*tree)->entries, te, entry);
546 buf += elen;
547 remain -= elen;
550 if (remain != 0) {
551 got_object_tree_close(*tree);
552 return got_error(GOT_ERR_BAD_OBJ_DATA);
555 return NULL;
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;
564 uint8_t *buf;
566 *outbuf = NULL;
567 *outlen = 0;
569 buf = calloc(1, blocksize);
570 if (buf == NULL)
571 return got_error(GOT_ERR_NO_MEM);
573 remain = blocksize;
574 total = 0;
575 while (1) {
576 if (remain == 0) {
577 uint8_t *newbuf;
578 newbuf = reallocarray(buf, 1, total + blocksize);
579 if (newbuf == NULL) {
580 err = got_error(GOT_ERR_NO_MEM);
581 goto done;
583 buf = newbuf;
584 remain += blocksize;
586 n = fread(buf, 1, remain, f);
587 if (n == 0) {
588 if (ferror(f)) {
589 err = got_ferror(f, GOT_ERR_IO);
590 goto done;
592 break; /* EOF */
594 remain -= n;
595 total += n;
596 };
598 done:
599 if (err == NULL) {
600 *outbuf = buf;
601 *outlen = total;
602 } else
603 free(buf);
604 return err;
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;
612 size_t len;
613 uint8_t *p;
614 int i, ret;
616 if (obj->flags & GOT_OBJ_FLAG_PACKED)
617 err = read_to_mem(&p, &len, f);
618 else
619 err = got_inflate_to_mem(&p, &len, f);
620 if (err)
621 return err;
623 if (len < obj->hdrlen + obj->size) {
624 err = got_error(GOT_ERR_BAD_OBJ_DATA);
625 goto done;
628 /* Skip object header. */
629 len -= obj->hdrlen;
630 err = parse_commit_object(commit, p + obj->hdrlen, len);
631 free(p);
632 done:
633 return err;
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;
641 FILE *f;
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);
648 else
649 err = open_loose_object(&f, obj, repo);
650 if (err)
651 return err;
653 err = read_commit_object(commit, repo, obj, f);
654 fclose(f);
655 return err;
658 void
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);
666 free(pid->id);
667 free(pid);
670 free(commit->tree_id);
671 free(commit->author);
672 free(commit->committer);
673 free(commit->logmsg);
674 free(commit);
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;
682 size_t len;
683 uint8_t *p;
684 int i, ret;
686 if (obj->flags & GOT_OBJ_FLAG_PACKED)
687 err = read_to_mem(&p, &len, f);
688 else
689 err = got_inflate_to_mem(&p, &len, f);
690 if (err)
691 return err;
693 if (len < obj->hdrlen + obj->size) {
694 err = got_error(GOT_ERR_BAD_OBJ_DATA);
695 goto done;
698 /* Skip object header. */
699 len -= obj->hdrlen;
700 err = parse_tree_object(tree, repo, p + obj->hdrlen, len);
701 free(p);
702 done:
703 return err;
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;
711 FILE *f;
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);
718 else
719 err = open_loose_object(&f, obj, repo);
720 if (err)
721 return err;
723 err = read_tree_object(tree, repo, obj, f);
724 fclose(f);
725 return err;
728 void
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);
739 free(tree);
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));
755 if (*blob == NULL)
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);
763 if (err)
764 return err;
765 } else {
766 err = open_loose_object(&((*blob)->f), obj, repo);
767 if (err) {
768 free(*blob);
769 return err;
772 err = got_inflate_init(&(*blob)->zb, blocksize);
773 if (err != NULL) {
774 fclose((*blob)->f);
775 free(*blob);
776 return err;
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);
787 return err;
790 void
791 got_object_blob_close(struct got_blob_object *blob)
793 if (blob->flags & GOT_BLOB_F_COMPRESSED)
794 got_inflate_end(&blob->zb);
795 else
796 free(blob->read_buf);
797 fclose(blob->f);
798 free(blob);
801 char *
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);
807 size_t
808 got_object_blob_get_hdrlen(struct got_blob_object *blob)
810 return blob->hdrlen;
813 const uint8_t *
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)
822 size_t n;
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);
830 *outlenp = n;
831 return NULL;