Commit 0e22967e43602d4c52a8d102e30107f8c4da765a

Stefan Sperling 2018-02-11T22:43:21

we must store delta's type-and-size length separately to skip it

diff --git a/lib/delta.c b/lib/delta.c
index 47d76d2..41af935 100644
--- a/lib/delta.c
+++ b/lib/delta.c
@@ -35,8 +35,8 @@
 #endif
 
 struct got_delta *
-got_delta_open(const char *path_packfile, int type, off_t offset,
-    size_t size)
+got_delta_open(const char *path_packfile, off_t offset, size_t tslen,
+    int type, size_t size)
 {
 	struct got_delta *delta;
 
@@ -51,6 +51,7 @@ got_delta_open(const char *path_packfile, int type, off_t offset,
 	}
 	delta->type = type;
 	delta->offset = offset;
+	delta->tslen = tslen;
 	delta->size = size;
 	return delta;
 }
@@ -224,11 +225,10 @@ copy_from_delta(const uint8_t **p, size_t *remain, size_t len, FILE *outfile)
 }
 
 const struct got_error *
-got_delta_apply(FILE *base_compressed, const uint8_t *delta_buf,
+got_delta_apply(FILE *base_file, const uint8_t *delta_buf,
     size_t delta_len, FILE *outfile)
 {
 	const struct got_error *err = NULL;
-	FILE *base_file = NULL;
 	uint64_t base_size, result_size;
 	size_t remain, outsize = 0;
 	const uint8_t *p;
@@ -259,22 +259,6 @@ got_delta_apply(FILE *base_compressed, const uint8_t *delta_buf,
 			err = parse_opcode(&offset, &len, &p, &remain);
 			if (err)
 				break;
-			if (base_file == NULL) {
-				size_t inflated_size;
-				base_file = got_opentemp();
-				if (base_file == NULL) {
-					err = got_error_from_errno();
-					break;
-				}
-				err = got_inflate_to_file(&inflated_size,
-				    base_compressed, base_file);
-				if (err)
-					break;
-				if (inflated_size != base_size) {
-					err = got_error(GOT_ERR_BAD_DELTA);
-					break;
-				}
-			}
 			err = copy_from_base(base_file, offset, len, outfile);
 			if (err == NULL)
 				outsize += len;
@@ -304,8 +288,6 @@ got_delta_apply(FILE *base_compressed, const uint8_t *delta_buf,
 	if (outsize != result_size)
 		err = got_error(GOT_ERR_BAD_DELTA);
 
-	if (base_file)
-		fclose(base_file);
 	if (err == NULL)
 		rewind(outfile);
 	return err;
diff --git a/lib/delta.h b/lib/delta.h
index 84193ca..1590576 100644
--- a/lib/delta.h
+++ b/lib/delta.h
@@ -18,6 +18,7 @@ struct got_delta {
 	SIMPLEQ_ENTRY(got_delta) entry;
 	char *path_packfile;
 	off_t offset;
+	size_t tslen;
 	int type;
 	size_t size;
 };
@@ -27,7 +28,7 @@ struct got_delta_chain {
 	SIMPLEQ_HEAD(, got_delta) entries;
 };
 
-struct got_delta *got_delta_open(const char *, int, off_t, size_t);
+struct got_delta *got_delta_open(const char *, off_t, size_t, int, size_t);
 void got_delta_close(struct got_delta *);
 const struct got_error *got_delta_chain_get_base_type(int *,
     struct got_delta_chain *);
diff --git a/lib/pack.c b/lib/pack.c
index 695e3dc..dd64e4a 100644
--- a/lib/pack.c
+++ b/lib/pack.c
@@ -548,8 +548,9 @@ parse_offset_delta(off_t *base_offset, FILE *packfile, off_t offset)
 	return NULL;
 }
 
-static const struct got_error *resolve_delta_chain(struct got_delta_chain *,
-    struct got_repository *repo, FILE *, const char *, int, off_t, size_t);
+static const struct got_error *
+resolve_delta_chain(struct got_delta_chain *, struct got_repository *,
+    FILE *, const char *, off_t, size_t, int, size_t);
 
 static const struct got_error *
 resolve_offset_delta(struct got_delta_chain *deltas,
@@ -576,7 +577,7 @@ resolve_offset_delta(struct got_delta_chain *deltas,
 		return err;
 
 	return resolve_delta_chain(deltas, repo, packfile, path_packfile,
-	    base_type, base_offset + base_tslen, base_size);
+	    base_offset, base_tslen, base_type, base_size);
 }
 
 static const struct got_error *
@@ -625,7 +626,8 @@ resolve_ref_delta(struct got_delta_chain *deltas, struct got_repository *repo,
 		goto done;
 
 	err = resolve_delta_chain(deltas, repo, base_packfile,
-	    path_base_packfile, base_type, base_offset + base_tslen, base_size);
+	    path_base_packfile, base_offset, base_tslen, base_type,
+	    base_size);
 done:
 	free(path_base_packfile);
 	if (base_packfile && fclose(base_packfile) == -1 && err == 0)
@@ -635,14 +637,14 @@ done:
 
 static const struct got_error *
 resolve_delta_chain(struct got_delta_chain *deltas, struct got_repository *repo,
-    FILE *packfile, const char *path_packfile, int delta_type,
-    off_t delta_offset, size_t delta_size)
+    FILE *packfile, const char *path_packfile, off_t delta_offset, size_t tslen,
+    int delta_type, size_t delta_size)
 {
 	const struct got_error *err = NULL;
 	struct got_delta *delta;
 
-	delta = got_delta_open(path_packfile, delta_type, delta_offset,
-	    delta_size);
+	delta = got_delta_open(path_packfile, delta_offset, tslen,
+	    delta_type, delta_size);
 	if (delta == NULL)
 		return got_error(GOT_ERR_NO_MEM);
 	deltas->nentries++;
@@ -705,7 +707,7 @@ open_delta_object(struct got_object **obj, struct got_repository *repo,
 	(*obj)->flags |= GOT_OBJ_FLAG_DELTIFIED;
 
 	err = resolve_delta_chain(&(*obj)->deltas, repo, packfile,
-	    path_packfile, delta_type, offset, delta_size);
+	    path_packfile, offset, tslen, delta_type, delta_size);
 	if (err)
 		goto done;
 
@@ -830,7 +832,8 @@ dump_delta_chain(struct got_delta_chain *deltas, FILE *outfile)
 			goto done;
 		}
 
-		if (fseeko(delta_file, delta->offset, SEEK_SET) != 0) {
+		if (fseeko(delta_file, delta->offset + delta->tslen,
+		    SEEK_SET) != 0) {
 			fclose(delta_file);
 			err = got_error_from_errno();
 			goto done;
@@ -856,6 +859,13 @@ dump_delta_chain(struct got_delta_chain *deltas, FILE *outfile)
 			continue;
 		}
 
+		if (delta->type == GOT_OBJ_TYPE_REF_DELTA &&
+		    fseeko(delta_file, SHA1_DIGEST_LENGTH, SEEK_CUR) != 0) {
+			fclose(delta_file);
+			err = got_error_from_errno();
+			goto done;
+		}
+
 		/* Delta streams should always fit in memory. */
 		err = got_inflate_to_mem(&delta_buf, &delta_len, delta_file);
 		fclose(delta_file);