Commit 6c00b54532f90be3b76dd1aed025376a35dc35de

Stefan Sperling 2018-01-17T21:59:05

open packed objects correctly; don't worry about their contents yet

diff --git a/include/got_object.h b/include/got_object.h
index 9e3f32b..204947b 100644
--- a/include/got_object.h
+++ b/include/got_object.h
@@ -73,9 +73,15 @@ struct got_object {
 #define GOT_OBJ_TYPE_OFFSET_DELTA	6
 #define GOT_OBJ_TYPE_REF_DELTA		7
 
+	int flags;
+#define GOT_OBJ_FLAG_PACKED		0x01
+
 	size_t hdrlen;
 	size_t size;
 	struct got_object_id id;
+
+	char *path_packfile;
+	off_t pack_offset;
 };
 
 struct got_repository;
diff --git a/lib/object.c b/lib/object.c
index a0ff6db..f3581b6 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -134,7 +134,7 @@ inflate_read(struct got_zstream_buf *zb, FILE *f, size_t *outlenp)
 			n = fread(zb->inbuf, 1, zb->inlen, f);
 			if (n == 0) {
 				if (ferror(f))
-					return got_error(GOT_ERR_IO);
+					return got_ferror(f, GOT_ERR_IO);
 				*outlenp = 0;
 				return NULL;
 			}
@@ -268,34 +268,26 @@ object_path(char **path, struct got_object_id *id, struct got_repository *repo)
 	return err;
 }
 
-static const struct got_error *
-open_object(FILE **f, struct got_object_id *id, struct got_repository *repo)
+const struct got_error *
+open_object(FILE **f, struct got_object *obj, struct got_repository *repo)
 {
 	const struct got_error *err = NULL;
 	char *path;
 
-	err = object_path(&path, id, repo);
+	if (obj->flags & GOT_OBJ_FLAG_PACKED) {
+		return got_error(GOT_ERR_NOT_IMPL);
+	}
+
+	err = object_path(&path, &obj->id, repo);
 	if (err)
 		return err;
-
 	*f = fopen(path, "rb");
 	if (*f == NULL) {
-		if (errno != ENOENT) {
-			err = got_error_from_errno();
-			goto done;
-		}
-		err = got_packfile_extract_object(f, id, repo);
-		if (err)
-			goto done;
-		if (*f == NULL) {
-			err = got_error(GOT_ERR_NO_OBJ);
-			goto done;
-		}
+		err = got_error_from_errno();
+		goto done;
 	}
 done:
 	free(path);
-	if (err && *f != NULL)
-		fclose(*f);
 	return err;
 }
 
@@ -303,24 +295,43 @@ const struct got_error *
 got_object_open(struct got_object **obj, struct got_repository *repo,
     struct got_object_id *id)
 {
-	const struct got_error *err;
+	const struct got_error *err = NULL;
+	char *path;
 	FILE *f;
 
-	err = open_object(&f, id, repo);
+	err = object_path(&path, id, repo);
 	if (err)
 		return err;
 
-	err = read_object_header(obj, repo, f);
-	if (err == NULL)
+	f = fopen(path, "rb");
+	if (f == NULL) {
+		if (errno != ENOENT) {
+			err = got_error_from_errno();
+			goto done;
+		}
+		err = got_packfile_open_object(obj, id, repo);
+		if (err)
+			goto done;
+		if (*obj == NULL)
+			err = got_error(GOT_ERR_NO_OBJ);
+	} else {
+		err = read_object_header(obj, repo, f);
+		if (err)
+			goto done;
 		memcpy((*obj)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH);
-	else
+	}
+done:
+	free(path);
+	if (err && f)
 		fclose(f);
 	return err;
+
 }
 
 void
 got_object_close(struct got_object *obj)
 {
+	free(obj->path_packfile);
 	free(obj);
 }
 
@@ -587,7 +598,7 @@ got_object_commit_open(struct got_commit_object **commit,
 	if (obj->type != GOT_OBJ_TYPE_COMMIT)
 		return got_error(GOT_ERR_OBJ_TYPE);
 
-	err = open_object(&f, &obj->id, repo);
+	err = open_object(&f, obj, repo);
 	if (err)
 		return err;
 
@@ -656,7 +667,7 @@ got_object_tree_open(struct got_tree_object **tree,
 	if (obj->type != GOT_OBJ_TYPE_TREE)
 		return got_error(GOT_ERR_OBJ_TYPE);
 
-	err = open_object(&f, &obj->id, repo);
+	err = open_object(&f, obj, repo);
 	if (err)
 		return err;
 
@@ -695,7 +706,7 @@ got_object_blob_open(struct got_blob_object **blob,
 	if (*blob == NULL)
 		return got_error(GOT_ERR_NO_MEM);
 
-	err = open_object(&((*blob)->f), &obj->id, repo);
+	err = open_object(&((*blob)->f), obj, repo);
 	if (err) {
 		free(*blob);
 		return err;
diff --git a/lib/pack.c b/lib/pack.c
index dc94a55..7e7325a 100644
--- a/lib/pack.c
+++ b/lib/pack.c
@@ -292,16 +292,15 @@ get_object_idx(struct got_packidx_v2_hdr *packidx, struct got_object_id *id)
 		i = betoh32(packidx->fanout_table[id0 - 1]);
 
 	while (i < totobj) {
-		struct got_object_id *oid = &packidx->sorted_ids[i++];
+		struct got_object_id *oid = &packidx->sorted_ids[i];
 		uint32_t offset;
 		int cmp = got_object_id_cmp(id, oid);
 
-		if (cmp < 0)
-			continue;
-		if (cmp > 0)
+		if (cmp == 0)
+			return i;
+		else if (cmp > 0)
 			break;
-
-		return i;
+		i++;
 	}
 
 	return -1;
@@ -328,36 +327,6 @@ read_packfile_hdr(FILE *f, struct got_packidx_v2_hdr *packidx)
 }
 
 static const struct got_error *
-dump_plain_object(FILE *infile, uint8_t type, uint64_t size, FILE *outfile)
-{
-	const char *type_tag = got_object_get_type_tag(type);
-	size_t n;
-
-	if (type_tag == NULL)
-		return got_error(GOT_ERR_OBJ_TYPE);
-
-	fprintf(outfile, "%s %llu", type_tag, size);
-	fputc('\0', outfile);
-
-	while (size > 0) {
-		uint8_t data[2048];
-		size_t len = MIN(size, sizeof(data));
-
-		n = fread(data, len, 1, infile);
-		if (n != 1)
-			return got_ferror(infile, GOT_ERR_BAD_PACKIDX);
-
-		n = fwrite(data, len, 1, outfile);
-		if (n != 1)
-			return got_ferror(outfile, GOT_ERR_BAD_PACKIDX);
-
-		size -= len;
-	}
-
-	return NULL;
-}
-
-static const struct got_error *
 decode_type_and_size(uint8_t *type, uint64_t *size, FILE *packfile)
 {
 	uint8_t t = 0;
@@ -392,63 +361,21 @@ decode_type_and_size(uint8_t *type, uint64_t *size, FILE *packfile)
 }
 
 static const struct got_error *
-dump_packed_object(FILE **f, FILE *packfile, off_t offset)
-{
-	const struct got_error *err = NULL;
-	const char *template = "/tmp/got.XXXXXXXXXX";
-	uint8_t type;
-	uint64_t size;
-	FILE *outfile = NULL;
-
-	*f = got_opentemp();
-	if (*f == NULL) {
-		err = got_error(GOT_ERR_FILE_OPEN);
-		goto done;
-	}
-
-	if (fseeko(packfile, offset, SEEK_SET) != 0) {
-		err = got_error_from_errno();
-		goto done;
-	}
-
-	err = decode_type_and_size(&type, &size, packfile);
-	if (err)
-		goto done;
-
-	switch (type) {
-	case GOT_OBJ_TYPE_COMMIT:
-	case GOT_OBJ_TYPE_TREE:
-	case GOT_OBJ_TYPE_BLOB:
-		err = dump_plain_object(packfile, type, size, *f);
-		break;
-	case GOT_OBJ_TYPE_REF_DELTA:
-	case GOT_OBJ_TYPE_TAG:
-	case GOT_OBJ_TYPE_OFFSET_DELTA:
-	default:
-		err = got_error(GOT_ERR_NOT_IMPL);
-		goto done;
-	}
-
-	rewind(*f);
-done:
-	if (err && *f)
-		fclose(*f);
-	return err;
-}
-
-static const struct got_error *
-extract_object(FILE **f, const char *path_packdir,
-    struct got_packidx_v2_hdr *packidx, struct got_object_id *id)
+open_packed_object(struct got_object **obj, struct got_repository *repo,
+    const char *path_packdir, struct got_packidx_v2_hdr *packidx,
+    struct got_object_id *id)
 {
 	const struct got_error *err = NULL;
 	int idx = get_object_idx(packidx, id);
 	off_t offset;
-	char *path_packfile;
-	FILE *packfile;
 	char hex[SHA1_DIGEST_STRING_LENGTH];
 	char *sha1str;
+	char *path_packfile;
+	FILE *packfile;
+	uint8_t type;
+	uint64_t size;
 
-	*f = NULL;
+	*obj = NULL;
 	if (idx == -1) /* object not found in pack index */
 		return NULL;
 
@@ -475,20 +402,55 @@ extract_object(FILE **f, const char *path_packdir,
 	if (err)
 		goto done;
 
-	printf("Dumping object at offset %llu\n", offset);
-	err = dump_packed_object(f, packfile, offset);
+	if (fseeko(packfile, offset, SEEK_SET) != 0) {
+		err = got_error_from_errno();
+		goto done;
+	}
+
+	err = decode_type_and_size(&type, &size, packfile);
 	if (err)
 		goto done;
 
+	*obj = calloc(1, sizeof(**obj));
+	if (*obj == NULL) {
+		err = got_error(GOT_ERR_NO_MEM);
+		goto done;
+	}
+
+	switch (type) {
+	case GOT_OBJ_TYPE_COMMIT:
+	case GOT_OBJ_TYPE_TREE:
+	case GOT_OBJ_TYPE_BLOB:
+		(*obj)->path_packfile = strdup(path_packfile);
+		if ((*obj)->path_packfile == NULL) {
+			err = got_error(GOT_ERR_NO_MEM);
+			goto done;
+		}
+		(*obj)->type = type;
+		(*obj)->flags = GOT_OBJ_FLAG_PACKED;
+		(*obj)->hdrlen = 0;
+		(*obj)->size = size;
+		memcpy(&(*obj)->id, id, sizeof((*obj)->id));
+		(*obj)->pack_offset = offset;
+		break;
+	case GOT_OBJ_TYPE_REF_DELTA:
+	case GOT_OBJ_TYPE_TAG:
+	case GOT_OBJ_TYPE_OFFSET_DELTA:
+	default:
+		err = got_error(GOT_ERR_NOT_IMPL);
+		goto done;
+	}
 done:
 	free(path_packfile);
+	if (err)
+		free(*obj);
 	if (packfile && fclose(packfile) == -1 && err == 0)
 		err = got_error_from_errno();
 	return err;
 }
 
 const struct got_error *
-got_packfile_extract_object(FILE **f, struct got_object_id *id,
+got_packfile_open_object(struct got_object **obj, struct got_object_id *id,
     struct got_repository *repo)
 {
 	const struct got_error *err = NULL;
@@ -525,10 +487,10 @@ got_packfile_extract_object(FILE **f, struct got_object_id *id,
 		if (err)
 			goto done;
 
-		err = extract_object(f, path_packdir, packidx, id);
+		err = open_packed_object(obj, repo, path_packdir, packidx, id);
 		if (err)
 			goto done;
-		if (*f != NULL)
+		if (*obj != NULL)
 			break;
 	}
 
diff --git a/lib/pack.h b/lib/pack.h
index 9e034eb..e26be48 100644
--- a/lib/pack.h
+++ b/lib/pack.h
@@ -121,5 +121,5 @@ const struct got_error *got_packidx_open(struct got_packidx_v2_hdr **,
     const char *);
 void got_packidx_close(struct got_packidx_v2_hdr *);
 
-const struct got_error *got_packfile_extract_object(FILE **,
+const struct got_error *got_packfile_open_object(struct got_object **,
     struct got_object_id *, struct got_repository *);