Commit 68482ea3f555f479c9342976a7fbacae381ffc05

Stefan Sperling 2017-11-27T05:13:16

implement open/close for blobs; add test which prints one

diff --git a/include/got_object.h b/include/got_object.h
index d13b60b..b96bf6e 100644
--- a/include/got_object.h
+++ b/include/got_object.h
@@ -14,12 +14,23 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+struct got_zstream_buf {
+	z_stream z;
+	char *inbuf;
+	size_t inlen;
+	char *outbuf;
+	size_t outlen;
+	int flags;
+#define GOT_ZSTREAM_F_HAVE_MORE 0x01
+};
+
 struct got_object_id {
 	u_int8_t sha1[SHA1_DIGEST_LENGTH];
 };
 
 struct got_blob_object {
-	char *dummy;
+	FILE *f;
+	struct got_zstream_buf zb;
 };
 
 struct got_tree_entry {
@@ -73,3 +84,8 @@ void got_object_commit_close(struct got_commit_object *);
 const struct got_error *got_object_tree_open(struct got_tree_object **,
     struct got_repository *, struct got_object *);
 void got_object_tree_close(struct got_tree_object *);
+const struct got_error *got_object_blob_open(struct got_blob_object **,
+    struct got_repository *, struct got_object *, size_t);
+void got_object_blob_close(struct got_blob_object *);
+const struct got_error *got_object_blob_read_block(struct got_blob_object *,
+    size_t *);
diff --git a/lib/object.c b/lib/object.c
index ba716d0..a48d2da 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -68,16 +68,6 @@ got_object_id_str(struct got_object_id *id, char *buf, size_t size)
 	return buf;
 }
 
-struct got_zstream_buf {
-	z_stream z;
-	char *inbuf;
-	size_t inlen;
-	char *outbuf;
-	size_t outlen;
-	int flags;
-#define GOT_ZSTREAM_F_HAVE_MORE 0x01
-};
-
 static void
 inflate_end(struct got_zstream_buf *zb)
 {
@@ -662,3 +652,57 @@ got_object_tree_close(struct got_tree_object *tree)
 
 	free(tree);
 }
+
+const struct got_error *
+got_object_blob_open(struct got_blob_object **blob,
+    struct got_repository *repo, struct got_object *obj, size_t blocksize)
+{
+	const struct got_error *err = NULL;
+	char *path;
+
+	if (obj->type != GOT_OBJ_TYPE_BLOB)
+		return got_error(GOT_ERR_OBJ_TYPE);
+
+	err = object_path(&path, &obj->id, repo);
+	if (err)
+		return err;
+
+	*blob = calloc(1, sizeof(**blob));
+	if (*blob == NULL) {
+		free(path);
+		return got_error(GOT_ERR_NO_MEM);
+	}
+
+	(*blob)->f = fopen(path, "rb");
+	if ((*blob)->f == NULL) {
+		free(*blob);
+		free(path);
+		return got_error(GOT_ERR_BAD_PATH);
+	}
+
+	err = inflate_init(&(*blob)->zb, blocksize);
+	if (err != NULL) {
+		fclose((*blob)->f);
+		free(*blob);
+		free(path);
+		return err;
+	}
+
+	free(path);
+	return err;
+}
+
+void
+got_object_blob_close(struct got_blob_object *blob)
+{
+	inflate_end(&blob->zb);
+	fclose(blob->f);
+	free(blob);
+}
+
+const struct got_error *
+got_object_blob_read_block(struct got_blob_object *blob, size_t *outlenp)
+{
+	return inflate_read(&blob->zb, blob->f, outlenp);
+}
+
diff --git a/lib/refs.c b/lib/refs.c
index b299fd1..a754c23 100644
--- a/lib/refs.c
+++ b/lib/refs.c
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <util.h>
+#include <zlib.h>
 
 #include "got_error.h"
 #include "got_object.h"
diff --git a/regress/repository/repository_test.c b/regress/repository/repository_test.c
index 395a24d..e5867e0 100644
--- a/regress/repository/repository_test.c
+++ b/regress/repository/repository_test.c
@@ -20,11 +20,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sha1.h>
+#include <zlib.h>
 
 #include "got_error.h"
 #include "got_object.h"
 #include "got_refs.h"
 #include "got_repository.h"
+#include "got_sha1.h"
 
 #define RUN_TEST(expr, name) \
 	if (!(expr)) { printf("test %s failed", (name)); failure = 1; }
@@ -184,6 +186,51 @@ repo_read_log(const char *repo_path)
 	return 1;
 }
 
+static int
+repo_read_blob(const char *repo_path)
+{
+	const char *blob_sha1 = "141f5fdc96126c1f4195558560a3c915e3d9b4c3";
+	const struct got_error *err;
+	struct got_repository *repo;
+	struct got_object_id id;
+	struct got_object *obj;
+	struct got_blob_object *blob;
+	char hex[SHA1_DIGEST_STRING_LENGTH];
+	int i;
+	size_t len;
+
+	if (!got_parse_sha1_digest(id.sha1, blob_sha1))
+		return 0;
+
+	err = got_repo_open(&repo, repo_path);
+	if (err != NULL || repo == NULL)
+		return 0;
+	err = got_object_open(&obj, repo, &id);
+	if (err != NULL || obj == NULL)
+		return 0;
+	if (obj->type != GOT_OBJ_TYPE_BLOB)
+		return 0;
+
+	err = got_object_blob_open(&blob, repo, obj, 64);
+	if (err != NULL)
+		return 0;
+
+	putchar('\n');
+	do {
+		err = got_object_blob_read_block(blob, &len);
+		if (err)
+			break;
+		for (i = 0; i < len; i++)
+			putchar(blob->zb.outbuf[i]);
+	} while (len != 0);
+	putchar('\n');
+
+	got_object_blob_close(blob);
+	got_object_close(obj);
+	got_repo_close(repo);
+	return (err == NULL);
+}
+
 int
 main(int argc, const char *argv[])
 {
@@ -200,6 +247,7 @@ main(int argc, const char *argv[])
 	}
 
 	RUN_TEST(repo_read_log(repo_path), "read_log");
+	RUN_TEST(repo_read_blob(repo_path), "read_blob");
 
 	return failure ? 1 : 0;
 }