Commit Diff


commit - 6c00b54532f90be3b76dd1aed025376a35dc35de
commit + 3ee5fc2109eca572a496f0da1a80fecfc8b56aea
blob - ebe18b51f48a920944e61349e59e0a689b6ef282
blob + b85bd54d8416997549d793f8e47ea9dc6dc802ed
--- include/got_error.h
+++ include/got_error.h
@@ -34,6 +34,7 @@
 #define GOT_ERR_BAD_PACKFILE	16
 #define GOT_ERR_NO_OBJ		17
 #define GOT_ERR_NOT_IMPL	18
+#define GOT_ERR_OBJ_NOT_PACKED	19
 
 static const struct got_error {
 	int code;
@@ -58,6 +59,7 @@ static const struct got_error {
 	{ GOT_ERR_BAD_PACKFILE,	"bad pack file" },
 	{ GOT_ERR_NO_OBJ,	"object not found" },
 	{ GOT_ERR_NOT_IMPL,	"feature not implemented" },
+	{ GOT_ERR_OBJ_NOT_PACKED,"object is not packed" },
 };
 
 const struct got_error * got_error(int code);
blob - f3581b6726ebe6258178022ac2703b58f32165bb
blob + 96d336a171264be9c2e02e38fbaa135a7859c3aa
--- lib/object.c
+++ lib/object.c
@@ -274,9 +274,8 @@ open_object(FILE **f, struct got_object *obj, struct g
 	const struct got_error *err = NULL;
 	char *path;
 
-	if (obj->flags & GOT_OBJ_FLAG_PACKED) {
-		return got_error(GOT_ERR_NOT_IMPL);
-	}
+	if (obj->flags & GOT_OBJ_FLAG_PACKED)
+		return got_packfile_extract_object(f, obj, repo);
 
 	err = object_path(&path, &obj->id, repo);
 	if (err)
blob - 7e7325a8f390d9822562634b04bd0eb7fc9da742
blob + 32b5af0d196466272bd3893c0d65454a8f1e4509
--- lib/pack.c
+++ lib/pack.c
@@ -327,7 +327,7 @@ read_packfile_hdr(FILE *f, struct got_packidx_v2_hdr *
 }
 
 static const struct got_error *
-decode_type_and_size(uint8_t *type, uint64_t *size, FILE *packfile)
+decode_type_and_size(uint8_t *type, uint64_t *size, size_t *len, FILE *packfile)
 {
 	uint8_t t = 0;
 	uint64_t s = 0;
@@ -357,6 +357,7 @@ decode_type_and_size(uint8_t *type, uint64_t *size, FI
 
 	*type = t;
 	*size = s;
+	*len = i * sizeof(sizeN);
 	return NULL;
 }
 
@@ -374,6 +375,7 @@ open_packed_object(struct got_object **obj, struct got
 	FILE *packfile;
 	uint8_t type;
 	uint64_t size;
+	size_t tslen;
 
 	*obj = NULL;
 	if (idx == -1) /* object not found in pack index */
@@ -407,7 +409,7 @@ open_packed_object(struct got_object **obj, struct got
 		goto done;
 	}
 
-	err = decode_type_and_size(&type, &size, packfile);
+	err = decode_type_and_size(&type, &size, &tslen, packfile);
 	if (err)
 		goto done;
 
@@ -431,7 +433,7 @@ open_packed_object(struct got_object **obj, struct got
 		(*obj)->hdrlen = 0;
 		(*obj)->size = size;
 		memcpy(&(*obj)->id, id, sizeof((*obj)->id));
-		(*obj)->pack_offset = offset;
+		(*obj)->pack_offset = offset + tslen;
 		break;
 	case GOT_OBJ_TYPE_REF_DELTA:
 	case GOT_OBJ_TYPE_TAG:
@@ -497,6 +499,78 @@ got_packfile_open_object(struct got_object **obj, stru
 done:
 	free(path_packdir);
 	if (packdir && closedir(packdir) != 0 && err == 0)
+		err = got_error_from_errno();
+	return err;
+}
+
+static const struct got_error *
+dump_plain_object(FILE *infile, uint8_t type, size_t size, FILE *outfile)
+{
+	size_t n;
+
+	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;
+	}
+
+	rewind(outfile);
+	return NULL;
+}
+
+const struct got_error *
+got_packfile_extract_object(FILE **f, struct got_object *obj,
+    struct got_repository *repo)
+{
+	const struct got_error *err = NULL;
+	FILE *packfile = NULL;
+
+	if ((obj->flags & GOT_OBJ_FLAG_PACKED) == 0)
+		return got_error(GOT_ERR_OBJ_NOT_PACKED);
+
+	*f = got_opentemp();
+	if (*f == NULL) {
+		err = got_error(GOT_ERR_FILE_OPEN);
+		goto done;
+	}
+
+	packfile = fopen(obj->path_packfile, "rb");
+	if (packfile == NULL) {
 		err = got_error_from_errno();
+		goto done;
+	}
+
+	if (fseeko(packfile, obj->pack_offset, SEEK_SET) != 0) {
+		err = got_error_from_errno();
+		goto done;
+	}
+
+	switch (obj->type) {
+	case GOT_OBJ_TYPE_COMMIT:
+	case GOT_OBJ_TYPE_TREE:
+	case GOT_OBJ_TYPE_BLOB:
+		err = dump_plain_object(packfile, obj->type, obj->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;
+	}
+done:
+	if (packfile)
+		fclose(packfile);
+	if (err && *f)
+		fclose(*f);
 	return err;
 }
blob - e26be48fe9e5fa02953cf19e02932e77d46a40d5
blob + 18a6071e88706cf03a4eb280c3b30f5cd73fc425
--- lib/pack.h
+++ lib/pack.h
@@ -123,3 +123,5 @@ void got_packidx_close(struct got_packidx_v2_hdr *);
 
 const struct got_error *got_packfile_open_object(struct got_object **,
     struct got_object_id *, struct got_repository *);
+const struct got_error *got_packfile_extract_object(FILE **,
+    struct got_object *, struct got_repository *);